Firebase

Firebase를 사용한 트위터 클론 코딩#11(Realtime Tweets)

PON_Z 2022. 7. 21. 16:26

- 트윗내용을 누가 적었는지 알기 위해 코드를 수정해 줄 것이다.

  App.js에서 user 정보를 담을 state를 추가하고

  AppRouter에 props를 전달한다.

  Router에서 이후 받은 props를 Home으로 전달해 준다.

 

// App.js

import React, { useEffect, useState } from "react";
import AppRouter from "components/Router";
import { authService } from "myFirebase";

function App() {
  // firebase가 프로그램을 초기화 하길 기다리기 위한 state
  const [init, setInit] = useState(false);
  // 로그인 여부 state
  const [isLoggedIn, setIsLoggedIn] = useState(false);
  // user 정보 state
  const [userObj, setUserObj] = useState(null);

  // user의 변화를 듣고 listen
  useEffect(() => {
    authService.onAuthStateChanged((user) => {
      if(user) {
        setIsLoggedIn(true);
        setUserObj(user);
      }
      else {
        setIsLoggedIn(false);
      }
      setInit(true);
    });
  }, []);

/*
  console.log(authService.currentUser);
  setInterval(() => {
    console.log.authService(authService.currentUser);
  }, 2000);
  */
  return (
    <>
    {init ? <AppRouter isLoggedIn={isLoggedIn} userObj={userObj} /> : "Initializing..."}
    <footer>&copy; {new Date().getFullYear()} PONZ</footer>
    </>
  );
}

export default App;
 
 
// Router.js
import React, { useEffect, useState } from "react";
import { BrowserRouter, Routes, Route} from "react-router-dom";
import Navigation from "components/Navigation";
import Home from "routes/Home";
import Auth from "routes/Auth";
import Profile from "routes/Profile";

const AppRouter = ({isLoggedIn, userObj}) => {
    return (
        <BrowserRouter>
            {isLoggedIn && <Navigation />}
            <Routes>
                {isLoggedIn ? (
                        <>
                        <Route path ="/Home" element={<Home userObj={userObj} />}/>
                        <Route path ="/Profile" element={<Profile />}/>
                        </>
                    ) : (
                        <>
                        <Route path ="/" element={<Auth />}/>
                        </>
                    )
                }
            </Routes>
        </BrowserRouter>
    );
};

export default AppRouter;

- 이제 Home.js에서 props를 받고 onSubmit createId 값으로

  userObj 넣어 Doc에 add할 때 같이 추가 되도록 하자

 

// Home.js

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

// for Home import
const Home = ({ userObj }) => {
    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"), {
            text: tweet,
            createdAt: Date.now(),
            creatorId: userObj.uid,
        });
        // 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;

- react app에서 I like it 을 트윗하면,

  아래와 같이 text와 createId가 같이 보인다.

 

- 이제 실시간으로 업데이트를 가져오기 위해 onSnapshot() 매서드를 사용할 것이다.

 

// Home.js

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

// for Home import
const Home = ({ userObj }) => {
    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 q = query(collection(dbService, "tweets"), orderBy("createdAt", "desc"));
        onSnapshot(q, (snapshot) => {
            const tweetArr = snapshot.docs.map((document) => ({
                id: document.id,
                ...document.data(),
            }));
            setTweets(tweetArr);
        })
    }, []);
   
    const onSubmit = async (event) => {
        // 아무것도 입력하지 않는 행위 방지
        event.preventDefault();
        // tweets collction에 tweet내용과 작성시간을 담은 Doc을 add
        await addDoc(collection(dbService, "tweets"), {
            text: tweet,
            createdAt: Date.now(),
            creatorId: userObj.uid,
        });
        // 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.text}</h4>
                </div>
            ))}
        </div>
    </div>
    );
};    

export default Home;

 

- 아래와같이 cc를 입력하면 realtime으로 결과가 갱신되는 것을 볼 수 있다.

 

 

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

728x90