Twitter Clone Coding

[Twitter Clone Coding] #3 NWEETING

jer0618 2022. 11. 5. 07:42

https://nomadcoders.co/nwitter

 

트위터 클론코딩 – 노마드 코더 Nomad Coders

React Firebase for Beginners

nomadcoders.co

*노마드코더 트위터 클론코딩 강의내용을 정리한 글입니다. 

**강의에서는 Firebase v8 를 사용했지만 여기서는 Firebase v9을 사용하여 구현했습니다.

 

Form and Database Setup

Form 생성

  • nweet을 작성하기 위한 form 생성
// Home.js

import React, { useState } from "react";

export default function Home() {
  const [nweet, setNweet] = useState("");

  const onSubmitHandler = (event) => {
    event.preventDefault();
  };

  const onChangeHandler = (event) => {
    setNweet(event.target.value);
  };

  return (
    <div>
      <form onSubmit={onSubmitHandler}>
        <input type="text" value={nweet} onChange={onChangeHandler} placeholder="What's on your mind?" maxLength={120} />
        <input type="submit" value="Nweet" />
      </form>
    </div>
  );
}

Datebase 설정

  • firebase 콘솔 ⇒ 빌드(develop) ⇒ Firestore Database(Cloud Firestore)
  • database 생성 (test mode)

  • fb.js 에 db관련 코드 추가
// fb.js

import { initializeApp } from "firebase/app";
import { getAuth } from "firebase/auth";
import { getFirestore } from "firebase/firestore";

const firebaseConfig = {
  apiKey: process.env.REACT_APP_API_KEY,
  authDomain: process.env.REACT_APP_AUTH_DOMAIN,
  projectId: process.env.REACT_APP_PROJECT_ID,
  storageBucket: process.env.REACT_APP_STORAGE_BUCKET,
  messagingSenderId: process.env.REACT_APP_MESSAGING_SENDER_ID,
  appId: process.env.REACT_APP_APP_ID,
};

const fbApp = initializeApp(firebaseConfig);

export const fbAuth = getAuth(fbApp);
export const fbStore = getFirestore(fbApp); // 추가

Nweeting!

https://console.firebase.google.com/project/nwitter-9aeb9/firestore/data/~2F

  • Cloud Firestore의 database는 NoSQL database
  • Mongo DB와 유사-

용어

  • Collection : 일종의 폴더
  • Document : 일종의 문서

Admin Page

  • 콘솔을 통해서 직접 데이터를 추가해줄 수 있음

onSubmit

https://firebase.google.com/docs/firestore/quickstart#web-version-9_2

// Home.js

// ...생략
const onSubmitHandler = async (event) => {
    event.preventDefault();
    try {
      const nweetData = {
        nweet,
        createdAt: new Date(),
        creatorId: userInfo.uid, // App.js에서 userInfo를 가져와서 할당
      };

      const res = await addDoc(collection(fbStore, "nweets"), nweetData);
      console.log(res);

      setNweet("");
    } catch (error) {
      console.log(error);
    }
  };
// ...생략
  • addDoc을 사용하여 db에 데이터 추가

Getting the Nweets

// Home.js

// ...생략
const getNweets = async (querySnapshot) => {
    try {
      const tempNweets = [];
      querySnapshot.docs.mapforEach((doc) => {
        tempNweets.push({ id: doc.id, ...doc.data() });
      });
			// map구문 사용가능
			// const tempNweets = querySnapshot.docs.map((doc) => ({ id: doc.id, ...doc.data() }));
      console.log(tempNweets);

      setNweets([...tempNweets]);
    } catch (error) {
      console.log(error);
    }
  };
// ...생략
  • getDocs를 사용하여 데이터를 가져옴
  • firebase에서 반환하는 데이터는 스냅샷의 형태 ⇒ 정보 조회를 위해 forEach와 data() 메소드 사용

TimeStamp

https://firebase.google.com/docs/reference/js/firestore_.timestamp

  • firebase에서 시간은 나노초 단위로 기록
  • JS에서 사용하기 위해서는 받아온 timestamp객체를 toDate()메소드를 사용해 JS Date객체로 변환 후 사용 가능
// Home.js

<div>
  {nweets.map((item, idx) => (
    <div key={`nweet-${idx}`}>
      <h4>{item.nweet}</h4>
      <span>{item.createdAt.toDate().toLocaleString()}</span> // timestamp객체 변환
    </div>
  ))}
</div>

Realtime Nweets

  • onSnapshot을 사용해서 이벤트리스너 등록 ⇒ 실시간 반영
useEffect(() => {
    onSnapshot(collection(fbStore, "nweets"), (querySnapshot) => getNweets(querySnapshot));
  }, []);

  const getNweets = (querySnapshot) => {
    try {
      const tempNweets = querySnapshot.docs.map((doc) => ({ id: doc.id, ...doc.data() }));
      console.log(tempNweets);

      setNweets([...tempNweets]);
    } catch (error) {
      console.log(error);
    }
  };

Delete and Update

  • Home.js에서 Nweet.js컴포넌트 분할 및 버튼 추가
  • 본인여부 판단
import React from "react";

export default function Nweet({ nweet, isOwner }) {
  return (
    <div>
      <h4>{nweet.nweet}</h4>
      <span>{nweet.createdAt.toDate().toLocaleString()}</span>
      {isOwner && (
        <>
          <button>Delete Nweet</button>
          <button>Edit Nweet</button>
        </>
      )}
    </div>
  );
}

Delete

  • deleteDoc함수 사용
const deleteNweet = async () => {
    const ok = window.confirm("Are you sure you want to delete this Nweet?");

    if (ok) await deleteDoc(doc(fbStore, "nweets", nweet.id));
  };

Update(Edit)

  • updateDoc함수를 사용
const updateNweet = async (event) => {
    event.preventDefault();
    updateDoc(doc(fbStore, "nweets", nweet.id), { nweet: newNweet });
    toggleEditing();
  };

전체코드

// Nweet.js
import { deleteDoc, doc, updateDoc } from "firebase/firestore";
import React, { useState } from "react";
import { fbStore } from "../fb";

export default function Nweet({ nweet, isOwner }) {
  const [editing, setEditing] = useState(false);
  const [newNweet, setNewNweet] = useState(nweet.nweet);

  const deleteNweet = async () => {
    const ok = window.confirm("Are you sure you want to delete this Nweet?");

    if (ok) await deleteDoc(doc(fbStore, "nweets", nweet.id));
  };

  const toggleEditing = () => setEditing((prev) => !prev);

  const updateNweet = async (event) => {
    event.preventDefault();
    updateDoc(doc(fbStore, "nweets", nweet.id), { nweet: newNweet });
    toggleEditing();
  };

  const onChangeHandler = (event) => {
    const value = event.target.value;
    setNewNweet(value);
  };

  return (
    <div>
      {editing ? (
        <>
          <form>
            <input type="text" value={newNweet} required onChange={onChangeHandler} />
            <input type="submit" value="update" onClick={updateNweet} />
          </form>
          <button onClick={toggleEditing}>Cancel</button>
        </>
      ) : (
        <>
          <h4>{nweet.nweet}</h4>
          <span>{nweet.createdAt.toDate().toLocaleString()}</span>
          {isOwner && (
            <>
              <button onClick={deleteNweet} name="delete">
                Delete Nweet
              </button>
              <button onClick={toggleEditing} name="edit">
                Edit Nweet
              </button>
            </>
          )}
        </>
      )}
    </div>
  );
}
반응형