Back-end/Firebase

[노마드코더] #3 CRUD

성중 2022. 3. 28. 23:03

Posting

Firebase에서 Firestore Database테스트 모드로 생성해준다

 

지역은 집이랑 가까운 곳으로.. (asia-northeast1)

Firebase Cloud Firestore 문서🔽

 

Cloud Firestore  |  Firebase Documentation

유연하고 확장 가능한 NoSQL 클라우드 데이터베이스를 사용해 클라이언트 측 개발 및 서버 측 개발에 사용되는 데이터를 저장하고 동기화하세요.

firebase.google.com

 Firestore Database는 NoSQL 형태로, collection(폴더)과 document(문서)로 구성된다

 

[src/fbase.js]

...
firebase.initializeApp(firebaseConfig);

export const firebaseInstance = firebase;
export const authService = firebase.auth();
export const dbService = firebase.firestore();

fbase.js에 firestore를 추가해준다

 

[src/routes/Home.js]

import React, { useState } from "react";
import { dbService } from "fbase";

const Home = () => {
  const [post, setPost] = useState("");
  const onSubmit = async (event) => {
    event.preventDefault();
    await dbService.collection("posts").add({
      post,
      createdAt: Date.now(),
    });
    setPost("");
  };
  const onChange = (event) => {
    const {
      target: { value },
    } = event;
    setPost(value);
  };
  return (
    <div>
      <form onSubmit={onSubmit}>
        <input
          value={post}
          onChange={onChange}
          type="text"
          placeholder="What's on your mind?"
          maxLength={120}
        />
        <input type="submit" value="Post" />
      </form>
    </div>
  );
};

export default Home;

기본적인 form으로 posts라는 collection에 post라는 document를 추가하도록 코드를 작성해준다

 

collection이 자동 생성되고 document와 안에 field 값이 잘 들어온다!

 

Getting the Posts

[src/routes/Home.js]

import React, { useState, useEffect } from "react";
import { dbService } from "fbase";

const Home = () => {
  const [post, setPost] = useState("");
  const [posts, setPosts] = useState([]);
  const getPosts = async () => {
    const dbPosts = await dbService.collection("posts").get();
    dbPosts.forEach((document) => {
      const postObject = {
        ...document.data(),
        id: document.id, // map 함수를 위해 id를 임의로 추가
      };
      // 이전 값들 앞에 forEach로 들어오는 데이터 붙이기
      setPosts((prev) => [postObject, ...prev]);
    });
  };
  useEffect(() => {
    getPosts();
}, []);
...
return (
...
      <div>
        {posts.map((post) => (
          <div key={post.id}>
            <h4>{post.post}</h4>
          </div>
        ))}
      </div>
...

useEffect로 Firestore Database collection 데이터를 배열로 받아와, map 함수로 UI에 뿌려주자

 

Realtime Posts

[src/components/App.js]

  const [userObj, setUserObj] = useState(null);
  useEffect(() => {
    // 사용자 정보 변화 감지
    authService.onAuthStateChanged((user) => {
      if (user) {
        setIsLoggedIn(true);
        setUserObj(user);
      } else {
        setIsLoggedIn(false);
      }
      setInit(true);
    });
  }, []);

App.js에서 user 데이터를 state로 받고 Home.js까지 props로 전달

 

  const [userObj, setUserObj] = useState(null);
  useEffect(() => {
    // 사용자 정보 변화 감지
    authService.onAuthStateChanged((user) => {
      user ? setUserObj(user) : setUserObj(null);
      setInit(true);
    });
  }, []);
  return (
    <>
      {init ? (
        <AppRouter isLoggedIn={Boolean(userObj)} userObj={userObj} />
      ) : (
        "Loading..."
      )}
      <footer>&copy; {new Date().getFullYear()} Firebase</footer>
    </>
  );
}

isLoggedIn 데이터를 userObj 데이터를 활용해 리팩토링 

 

[src/routes/Home.js]

import React, { useState, useEffect } from "react";
import { dbService } from "fbase";

const Home = (props) => {
  const [post, setPost] = useState("");
  const [posts, setPosts] = useState([]);
  useEffect(() => {
    dbService.collection("posts").onSnapshot((snapshot) => {
      const postArray = snapshot.docs.map((doc) => ({
        id: doc.id,
        ...doc.data(),
      }));
      setPosts(postArray);
    });
  }, []);
  const onSubmit = async (event) => {
    event.preventDefault();
    await dbService.collection("posts").add({
      text: post,
      createdAt: Date.now(),
      creatorId: props.userObj.uid, // 작성한 유저 id
    });
    setPost("");
  };
  const onChange = (event) => {
    const {
      target: { value },
    } = event;
    setPost(value);
  };
  return (
    <div>
      <form onSubmit={onSubmit}>
        <input
          value={post}
          onChange={onChange}
          type="text"
          placeholder="What's on your mind?"
          maxLength={120}
        />
        <input type="submit" value="Post" />
      </form>
      <div>
        {posts.map((post) => (
          <div key={post.id}>
            <h4>{post.text}</h4>
          </div>
        ))}
      </div>
    </div>
  );
};

export default Home;

Home.js의 onSubmit 함수에 작성한 유저 id 정보를 추가할 수 있다!

데이터를 useEffect에서 snapshot으로 받아오는 방식으로 변경, 새로고침 없이 업데이트된다

 

Delete and Update

[src/components/Post.js]

import React from "react";

const Post = (props) => {
  return (
    <div>
      <h4>{props.postObj.text}</h4>
      {props.isOwner && (
        <>
          <button>Delete Post</button>
          <button>Update Post</button>
        </>
      )}
    </div>
  );
};

export default Post;

[src/routes/Home.js]

...
      <div>
        {posts.map((post) => (
          <Post
            key={post.id}
            postObj={post}
            isOwner={post.creatorId === props.userObj.uid}
          />
        ))}
      </div>
...

글을 Post 컴포넌트로 빼고, 작성자가 user 데이터와 일치한다면 수정/삭제 버튼이 보이도록 해준다

 

[src/components/Post.js]

import React, { useState } from "react";
import { dbService } from "fbase";

const Post = (props) => {
  const [editing, setEditing] = useState(false);
  const [newPost, setNewPost] = useState(props.postObj.text);
  const onDeleteClick = async () => {
    const ok = window.confirm("정말 삭제할까용?");
    if (ok) {
      await dbService.doc(`posts/${props.postObj.id}`).delete();
    }
  };
  const toggleEditing = () => setEditing((prev) => !prev);
  const onSubmit = async (event) => {
    event.preventDefault();
    await dbService.doc(`posts/${props.postObj.id}`).update({ text: newPost });
    setEditing(false);
  };
  const onChange = (event) => {
    const {
      target: { value },
    } = event;
    setNewPost(value);
  };
  return (
    <div>
      {editing ? (
        <>
          <form onSubmit={onSubmit}>
            <input
              value={newPost}
              onChange={onChange}
              type="text"
              placeholder="Edit your post"
              required
            />
            <input type="submit" value="Update" />
          </form>
          <button onClick={toggleEditing}>Cancel</button>
        </>
      ) : (
        <>
          <h4>{props.postObj.text}</h4>
          {props.isOwner && (
            <>
              <button onClick={onDeleteClick}>Delete Post</button>
              <button onClick={toggleEditing}>Update Post</button>
            </>
          )}
        </>
      )}
    </div>
  );
};

export default Post;

firestore 함수로 글의 수정/삭제가 가능하도록 코드를 추가해준다

 

본 내용은 노마드코더의 '트위터 클론코딩'을 바탕으로 작성되었습니다.

 

'Back-end > Firebase' 카테고리의 다른 글

[노마드코더] #5 Edit Profile  (0) 2022.04.08
[노마드코더] #4 File Upload  (0) 2022.04.06
[노마드코더] #2 Authentication  (0) 2022.03.18
[노마드코더] #1 Introduction  (0) 2022.03.11
[TIL] Firebase 기초  (2) 2022.03.08