Firebase

Firebase를 사용한 트위터 클론 코딩#10(Tweeting)

PON_Z 2022. 7. 15. 16:05

- Firebase DB는 NoSQL DB이다. 

  때문에 간단하고 자유롭지만 제약사항 약간 존재한다.

 

- NoSQL DB는 두 가지 요소를 가지는데

 Collection과 Document이다.

 Collection은 기본적으로 폴더와 비슷하고,

 Document는 말 그대로 doc 텍스트 같은 것이다.

 DB는 Collection들을 가지고 있고

 Collection은 Document들을 가진다.

 

- 컬렉션 추가를 눌러서 Collection이름을 "Tweets"으로,

  "content" 필드를 string 타입으로 선언해보았따.

 

 

- DB에 대해 알아보았으니 이제 코드상으로 구현해보자.

  우선 myFirebase에 dbService를 추가하자.

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,
    databaseURL: process.env.REACT_APP_DATABASE_URL,
    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,
    measurementId: process.env.REACT_APP_MEASUREMENT_ID,
  };

const firebaseApp = initializeApp(firebaseConfig);

export const authService = getAuth();
export const dbService = getFireStore();

- 그리고 Home에서 tweet를 submit할 때 마다 document를 생성하도록 코드를 작성해야 한다.

  Collection docs을 참고하자.

- 예전 버전과 다르게 사용방법이 달라진 사항이 많아서 코드에 수정사항이 좀 있었다.

 

// Home.js

import React, { useState } from "react";
import { dbService } from "myFirebase";
import { addDoc, collection } from "firebase/firestore";

// for Home import
const Home = () => {
    const [tweet, setTweet] = useState("");
   
    const onSubmit = async (event) => {
        // 아무것도 입력하지 않는 행위 방지
        event.preventDefault();
        // tweets collction에 tweet내용과 작성시간을 담은 Doc을 add
        await addDoc(collection(dbService, "tweets"), {
            tweet,
            createdAt: Date.now(),
        });
        // add한 이후 tweet을 빈 문자열로 초기화
        setTweet("");
    };

    const onChange = (event) => {
        const {
            target: { value },          
        } = event;
        setTweet(value);
    };

    return (
        <div>
        <form onSubmit={onSubmit}>
            <input
                value={tweet}
                onChange={onChange}
                type="text"
                placeholder="what's on your mind?"
                maxLength={120}
            />
            <input
                type="submit"
                value="Tweet"
            />
        </form>
    </div>
    );
}    

export default Home;

// myFirebase.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,
    databaseURL: process.env.REACT_APP_DATABASE_URL,
    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,
    measurementId: process.env.REACT_APP_MEASUREMENT_ID,
  };

const firebaseApp = initializeApp(firebaseConfig);

export const authService = getAuth(firebaseApp);
export const dbService = getFirestore(firebaseApp);

- 코드를 작성하고 hello를 트윗하면

 

- firestore에 tweets Collection이 자동으로 생겼고

  Collection 안에 tweet 내용과 date 시간을 담은 Document가

  생성된 것을 볼 수 있다.

 

 

- 이제 트윗을 받아올 것이다.

 

import React, { useEffect, useState } from "react";
import { dbService } from "myFirebase";
import { addDoc, collection, getDocs } from "firebase/firestore";

// for Home import
const Home = () => {
    const [tweet, setTweet] = useState("");
    const [tweets, setTweets] = useState([]);

    const getTweets = async () => {
        const dbTweets = await getDocs(collection(dbService, "tweets"));
        dbTweets.forEach((doc) => {
            const tweetObject = {
                ...doc.data(),
                id: doc.id,
            };
            setTweets((prev) => [tweetObject, ...prev]);
        });
    }

    useEffect(() => {
        getTweets();
    }, []);
   
    const onSubmit = async (event) => {
        // 아무것도 입력하지 않는 행위 방지
        event.preventDefault();
        // tweets collction에 tweet내용과 작성시간을 담은 Doc을 add
        await addDoc(collection(dbService, "tweets"), {
            tweet,
            createdAt: Date.now(),
        });
        // add한 이후 tweet을 빈 문자열로 초기화
        setTweet("");
    };

    const onChange = (event) => {
        const {
            target: { value },          
        } = event;
        setTweet(value);
    };

    return (
        <div>
        <form onSubmit={onSubmit}>
            <input
                value={tweet}
                onChange={onChange}
                type="text"
                placeholder="what's on your mind?"
                maxLength={120}
            />
            <input
                type="submit"
                value="Tweet"
            />
        </form>
        <div>
            {tweets.map((tweet) => (
                <div key={tweet.id}>
                    <h4>{tweet.tweet}</h4>
                </div>
            ))}
        </div>
    </div>
    );
};    

export default Home;
- 아래처럼 두 번 호출되길래 오류가 있는 줄 알았는데 알고보니
  side effect를 줄이기 위해 일부러 두 번씩 실행된다고 한다.
  그래서 dev환경에서만 두 번씩 호출되고 production에서는 무시된다고 한다.

- ref) https://nomadcoders.co/nwitter/lectures/

728x90