21.10.24 ๊ณต๋ถ€๊ธฐ๋ก๐Ÿง‘โ€๐Ÿ’ป

devduckยท2021๋…„ 10์›” 24์ผ
3
post-thumbnail

FireBase, React๋ฅผ ํ™œ์šฉํ•œ ํŠธ์œ„ํ„ฐ ํด๋ก ์ฝ”๋”ฉ๐Ÿง‘โ€๐Ÿ’ป


์˜ค๋Š˜ ์™„๋ฃŒํ•œ ๋ชฉ๋ก
1. ์ด ํŠธ์œ— ์“ด ์‚ฌ๋žŒ ๋ˆ„๊ตฌ์—ฌ
2. ์‹ค์‹œ๊ฐ„ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋กœ ํŠธ์œ— ๋ชฉ๋ก ํ™”๋ฉด์— ๋‚˜ํƒ€๋‚ด๊ธฐ
3. ํ›„๋ฐ˜ ์ฝ”๋“œ ์ž‘์—…์„ ์œ„ํ•œ ์ปดํฌ๋„ŒํŠธ ๋ถ„๋ฆฌ ๋ฐ ํŠธ์œ— ์‚ญ์ œ ๋ฐ ์ˆ˜์ • ๊ถŒํ•œ ๋ถ€์—ฌ
4. ํŠธ์œ— ์‚ญ์ œ ๋ฐ ์ˆ˜์ • ๊ธฐ๋Šฅ ~ing


1. ์ด ํŠธ์œ— ์“ด ์‚ฌ๋žŒ ๋ˆ„๊ตฌ์—ฌ

app.js

const [userObj, setUserObj] = useState(null); 
// ๋กœ๊ทธ์ธ ์ •๋ณด๊ด€๋ฆฌ๋ฅผ ์œ„ํ•œ useState
useEffect(() => {
    auth.onAuthStateChanged((user) =>{
      if(user){
        setIsLoggedIn(true);
        setUserObj(user);
      }else{
        setIsLoggedIn(false)
      }
      setInit(true);
    });
  }, []);

return (
    <>
  {init ? <AppRouter isLoggedIn = {isLoggedIn} userObj={userObj} /> : "Initialzizing.."} 
  {/* userObj๋ฅผ AppRouter์„ ์ด์šฉํ•˜์—ฌ ๋ณด๋ƒ„ */}
  <footer>&copy; {new Date().getFullYear()} Nwitter</footer>
   </>
  )

ํŠธ์œ—์˜ ์•„์ด๋””๋ฅผ ์ €์žฅํ•˜์ง€ ์•Š์œผ๋ฉด ๋ˆ„๊ฐ€ ์–ด๋–ค ํŠธ์œ—์„ ์ผ๋Š”์ง€ ์•Œ ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์—
๋กœ๊ทธ์ธ ์ •๋ณด๊ด€๋ฆฌ๋ฅผ ์œ„ํ•ด useState๋ฅผ ํ™œ์šฉํ•˜์—ฌ userObjํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค์—ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  if๋ฌธ์„ ์ด์šฉํ•˜์—ฌ
๋งŒ์•ฝ user๋ผ๋ฉด userObjํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•˜์—ฌ id๋ฅผ ๋‚ด๋ณด๋‚ด๊ฒŒ ํ–ˆ๋‹ค.
๊ทธ๋ฆฌ๊ณ  ๋‚ด๊ฐ€ app.js์—์„œ ๋งŒ๋“  userObjํ•จ์ˆ˜๋ฅผ ๋‹ค๋ฅธ ๊ณณ์—์„œ๋„ ์“ฐ๊ธฐ ์œ„ํ•ด
AppRouter์„ ํ†ตํ•ด ๋ณด๋ƒˆ๋‹ค.

๋ณด๋ฉด creatorID๊ฐ€ ์ข€ ๋งŽ์ด ์น ํ•ด์ ธ์„œ ์•ˆ๋ณด์ด์ง€๋งŒ ์•„์ด๋””๊ฐ€ ๋™์ผํ•˜๋‹ค.


2. ์‹ค์‹œ๊ฐ„ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋กœ ํŠธ์œ— ๋ชฉ๋ก ํ™”๋ฉด์— ๋‚˜ํƒ€๋‚ด๊ธฐ

home.js

์ „)

const [nweets, setNweets] = useState([]); 
//  ํŠธ์œ—๋“ค์„  ์ƒํƒœ๋กœ ๋ฐ›์•„์„œ ๋ณด๊ด€ํ•ด์•ผํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ฐฐ์—ด๋กœ usestate ์ƒ์„ฑ
const getNweets = async ()=> {
        const q = query(collection(dbService,"nweets"));
        const querySnapshot = await getDocs(q);
        querySnapshot.forEach((doc) => {
        const nweetObj = { //nweetObj => ํŠธ์œ— ๋‚ด์šฉ 
            ...doc.data(), 
            id:doc.id,
        } 
         setNweets(prev => [nweetObj,...prev]);   
        });

ํ›„)

const [nweets, setNweets] = useState([]);
//  ํŠธ์œ—๋“ค์„  ์ƒํƒœ๋กœ ๋ฐ›์•„์„œ ๋ณด๊ด€ํ•ด์•ผํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ฐฐ์—ด๋กœ usestate ์ƒ์„ฑ
useEffect(() => {
        onSnapshot( 
        query(collection(dbService, "nweets"), orderBy("createdAt", "desc")),
        (snapshot) => {
        const nweetArray = snapshot.docs.map((doc) => ({
        id: doc.id, 
        ...doc.data(), 
        }));
        setNweets(nweetArray);
        }
        );
        }, []);

์‹ค์‹œ๊ฐ„์œผ๋กœ ํŠธ์œ— ๋ชฉ๋ก์„ ๋ณด์—ฌ์ฃผ๊ธฐ ์œ„ํ•ด์„œ ๋จผ์ € ๊ธฐ์กด์— ์“ฐ๋˜ ๊ตฌ์กฐ๋ฅผ ๊ฐˆ์•„์—Ž์—ˆ๋‹ค..ใ…Žใ…Ž
๊ธฐ์กด์— ์“ฐ๋˜ getNweets๋ฅผ ์—†์• ๊ณ  ํŒŒ์ด์–ด๋ฒ ์ด์Šค์˜ onSnapshot ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ–ˆ๋‹ค.
์ด ํ•จ์ˆ˜๋Š” ์ •๋ง ๋„ˆ๋ฌด๋„ˆ๋ฌด ์œ ์šฉํ–ˆ๋Š”๋ฐ ์ด ํ•จ์ˆ˜ ํ•˜๋‚˜๋กœ ์‹ค์‹œ๊ฐ„ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋ฐ์ดํ„ฐ๋ฅผ ๋ถˆ๋Ÿฌ์˜ฌ ์ˆ˜ ์žˆ์—ˆ๋‹ค.

์ž์„ธํ•œ ์„ค๋ช…ํ•˜์ž๋ฉด, onSnapshotํ•จ์ˆ˜๋Š” ๋ชจ๋“  ์Šค๋ƒ…์ƒท์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
๊ทธ๋ ‡๊ฒŒ ๋ฐ›์€ snapshot์—์„œ ์›ํ•˜๋Š” ๋ฐ์ดํ„ฐ๋งŒ ๋ฝ‘๊ธฐ ์œ„ํ•ด์„œ mapํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ–ˆ๋‹ค.
์ „์— ์žˆ๋˜ ์ฝ”๋“œ๋Š” forEachํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•˜์—ฌ ์ˆœํ™˜ํ•  ๋•Œ๋งˆ๋‹ค setNweetsํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ–ˆ์–ด์•ผ ํ–ˆ์ง€๋งŒ
mapํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•˜์—ฌ ์ˆœํšŒํ•˜๋ฉด์„œ ๋ฐ›์€ ๋ฐฐ์—ด์„ ๋ฐ˜ํ™˜ํ•˜๊ธฐ ๋•Œ๋ฌธ์— setNweetํ•จ์ˆ˜์— ๋‹จ 1๋ฒˆ๋งŒ ๋ฐฐ์—ด์„ ์ „๋‹ฌํ•˜๋ฉด ๋˜์„œ ํ›จ์”ฌ ํšจ์œจ์ ์ด๋‹ค!


3. ํ›„๋ฐ˜ ์ฝ”๋“œ ์ž‘์—…์„ ์œ„ํ•œ ์ปดํฌ๋„ŒํŠธ ๋ถ„๋ฆฌ ๋ฐ ํŠธ์œ— ์‚ญ์ œ ๋ฐ ์ˆ˜์ • ๊ถŒํ•œ ๋ถ€์—ฌ

์ ์  ์ฝ”๋“œ๋ฅผ ์ ์–ด๋‚˜๊ฐˆ ์ˆ˜๋ก home.js์˜ ์ปดํฌ๋„ŒํŠธ์— ์ถ”๊ฐ€ํ•ด์•ผํ•œ๋‹ค. ๊ทธ๋ ‡๊ฒŒ ๋˜๋ฉด
์ฝ”๋“œ์˜ ๋ฉ์น˜๋„ ์ปค์ง€๊ณ  ๋ณด๊ธฐ์—๋„ ์•ˆ ์ข‹๊ธฐ ๋•Œ๋ฌธ์— ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ถ„๋ฆฌํ–ˆ๋‹ค.
๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— Nweet.js๋กœ ๋ณ„๋„๋กœ ํŠธ์œ—์šฉ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” ํŒŒ์ผ์„ ๋งŒ๋“ค์—ˆ๋‹ค.

Nweet.js

import React from "react";

const Nweet = ({nweetObj, isOwner}) =>{
    }
    return (
    <div>
        <h4>{nweetObj.nweet}</h4>
        {isOwner && (
            <>
                <button>Delete tweet</button>
                <button>Edit Nweet</button>            
            </>
        )}
    </div>

    );
};

export default Nweet;

๊ธฐ์กด์˜ home์˜ ์ปดํฌ๋„ŒํŠธ์™€ ๋‹ค๋ฅธ ๊ฒƒ์€ home ์ปดํฌ๋„ŒํŠธ์˜ map ํ•จ์ˆ˜์—์„œ ๋ฐ˜ํ™˜ํ•˜๋Š” nweetObj ๋ฐฐ์—ด์„
ํ”„๋กญ์Šค๋กœ ๋ฐ›๋Š”๋‹ค๋Š” ๊ฒƒ๋งŒ ๋‹ค๋ฅด๋‹ค.
Nweet ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋งŒ๋“ค์–ด ์‚ญ์ œ์™€ ์ˆ˜์ •์„ ์œ„ํ•œ ๋ฒ„ํŠผ์„ ๋งŒ๋“ค์—ˆ๋‹ค.

home.js

import Nweet from "components/Nweet";
<div> 
        {nweets.map((nweet) => (
// map ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•˜์—ฌ nweets ๋ฐฐ์—ด์„ ์ˆœํšŒํ•˜๋ฉด์„œ jsx๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ฒŒ ๋งŒ๋“ค์–ด์„œ ํŠธ์œ— ๋ฐฐ์—ด๋“ค์„ ์›น์— ๋‚˜ํƒ€๋ƒ„.
        <Nweet 
        key={nweet.id} 
        nweetObj={nweet}
        isOwner={nweet.creatorId === userObj.uid}
         // isOwner  nweet.creatorId === userObj.uid๊ฐ€ ๊ฐ™์•„์•ผ ๊ถŒํ•œ์„ ์ค„ ์ˆ˜ ์žˆ๊ฒŒ ์„ค์ •.
        />
            ))}
    </div>

์ด์ œ home.js์—์„œ ์œ„์—์„œ ๋งŒ๋“  nweet์ปดํฌ๋„ŒํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด import ํ–ˆ๊ณ 
nweet ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ž…๋ ฅํ–ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ์ˆ˜์ • ๋ฐ ์‚ญ์ œ ๊ถŒํ•œ์„ ์ € ํŠธ์œ—์„ ์“ด ์‚ฌ์šฉ์ž๋งŒ ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•˜๊ธฐ ์œ„ํ•ด์„œ ์œ„์—๋„ ์žˆ์ง€๋งŒ ์ž์„ธํžˆ ์„ค๋ช…ํ•˜๋ฉด,
home.js์—๋Š”

isOwner={nweet.creatorId === userObj.uid}

์ถ”๊ฐ€ํ–ˆ๊ณ  Nweet.js์—์„œ Nweet ์ปดํฌ๋„ŒํŠธ์—์„œ isOwner๋ผ๋Š” ํ”„๋กญ์Šค๋„ ๋ฐ›๊ฒŒ ํ–ˆ๋‹ค.
ํŠธ์œ— ์ž‘์„ฑ์ž์˜ ์•„์ด๋””๋กœ ๋ดค์„ ๋•Œ

๋‹ค๋ฅธ ์‚ฌ์šฉ์ž๋กœ ๋ดค์„ ๋•Œ


4. ํŠธ์œ— ์‚ญ์ œ ๋ฐ ์ˆ˜์ • ๊ธฐ๋Šฅ ~ing

ํŠธ์œ— ์‚ญ์ œ๊ธฐ๋Šฅ์„ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด์„œ ํ•จ์ˆ˜ํ•˜๋‚˜๋งŒ ํ˜„์žฌ ๋งŒ๋“ค์–ด๋†“์€ ์ƒํƒœ๋‹ค ^^
nweet.js์˜ nweet ์ปดํฌ๋„ŒํŠธ ์•ˆ์— ์ถ”๊ฐ€ํ•ด์คฌ๋‹ค.

const onDeleteClick = () => {
        const ok = window.confirm("Are you sure you want to delete this tweet?");
        if(ok){
            //delete tweet
        }

์ด๊ฑฐ๋Š” ๋ญ.. ์ฐฝ์œผ๋กœ ์ง„์งœ ์‚ญ์ œํ• ๊ฑฐ๋ƒ๊ณ  ๋œจ๊ฒŒ๋งŒ ์ผ๋‹จ ํ•ด๋†จ๋‹ค


์ „์ฒด ์ฝ”๋“œ

nweet.js

import React from "react";

const Nweet = ({nweetObj, isOwner}) =>{
    const onDeleteClick = () => {
        const ok = window.confirm("Are you sure you want to delete this tweet?");
        if(ok){
            //delete tweet
        }

    }
    return (
    <div>
        <h4>{nweetObj.nweet}</h4>
        {isOwner && (
            <>
                <button>Delete tweet</button>
                <button>Edit Nweet</button>            
            </>
        )}
    </div>

    );
};

export default Nweet;

home.js

import { dbService } from 'fbase';
import React,{useState, useEffect} from "react";
import {addDoc, collection,query, onSnapshot,orderBy} from "firebase/firestore";
import Nweet from "components/Nweet"

const Home = ({userObj}) => {
    const [nweet, setNweet] = useState("");
    const [nweets, setNweets] = useState([]); //  ํŠธ์œ—๋“ค์„  ์ƒํƒœ๋กœ ๋ฐ›์•„์„œ ๋ณด๊ด€ํ•ด์•ผํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ฐฐ์—ด๋กœ usestate ์ƒ์„ฑ
    
    useEffect(() => {
        onSnapshot( // OnSnapshot ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•˜์—ฌ ๋ชจ๋“  ์Šค๋ƒ…์ƒท์„ ๋ฐ˜ํ™˜ํ•จ.
        query(collection(dbService, "nweets"), orderBy("createdAt", "desc")),
        (snapshot) => {
        const nweetArray = snapshot.docs.map((doc) => ({
        id: doc.id, // map ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•˜์—ฌ ์Šค๋ƒ…์ƒท์—์„œ ์›ํ•˜๋Š” ๋ฐ์ดํ„ฐ๋งŒ ๋ฝ‘์•„์„œ ๋ฐฐ์—ดํ™” ์‹œํ‚จ ํ›„ ํ™”๋ฉด์— ๋‚˜ํƒ€๋ƒ„.
        ...doc.data(), // ์ „์— ์‚ฌ์šฉํ–ˆ๋˜ Foreachํ•จ์ˆ˜๋Š” ๋งค ์ˆœํšŒ๋งˆ๋‹ค setNweets๋ฅผ ์‚ฌ์šฉํ•ด์•ผํ•˜์ง€๋งŒ, mapํ•จ์ˆ˜๋Š” ์ˆœํšŒํ•˜๋ฉด์„œ ๋งŒ๋“  ๋ฐฐ์—ด์„ ๋ฐ˜ํ™˜ํ•˜๋ฏ€๋กœ
                        // ๋ฐ˜ํ™˜ํ•œ ๋ฐฐ์—ด์„ 1๋ฒˆ๋งŒ setNweetํ•จ์ˆ˜์— ์ „๋‹ฌํ•˜๋ฉด ๋˜๊ธฐ ๋•Œ๋ฌธ์— ํ›จ์”ฌ ํšจ์œจ์ ์ด๋‹ค.
        }));
        setNweets(nweetArray);
        }
        );
        }, []);


    const onSubmit = async (e) => {
        try{
        e.preventDefault();
        const docRef = await addDoc(collection(dbService, "nweets"),
            {
            nweet,
            createdAt: Date.now(),
            creatorId : userObj.uid, // db์— ์œ ์ €์•„์ด๋”” ์ถ”๊ฐ€
        }); // ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ƒ์„ฑ 
        console.log("Document Written with Id:", docRef.id);
        }catch(error){
            console.log("Error adding document", error)
        }

        setNweet("");
    };
    const onChange = (event) =>{
        const {target : {value},
        }= event;
        setNweet(value);
    };
    console.log(nweets);

return (
 <>   
<div>
    <form onSubmit={onSubmit}>
        <input value={nweet} onChange={onChange} type = "text" placeholder ="what's on your mind" maxLength={120} />
        <input type="submit" value="nweet"/>
    </form>
    <div> 
        {nweets.map((nweet) => (
// map ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•˜์—ฌ nweets ๋ฐฐ์—ด์„ ์ˆœํšŒํ•˜๋ฉด์„œ jsx๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ฒŒ ๋งŒ๋“ค์–ด์„œ ํŠธ์œ— ๋ฐฐ์—ด๋“ค์„ ์›น์— ๋‚˜ํƒ€๋ƒ„.
        <Nweet 
        key={nweet.id} 
        nweetObj={nweet}
        isOwner={nweet.creatorId === userObj.uid}
         // isOwner  nweet.creatorId === userObj.uid๊ฐ€ ๊ฐ™์•„์•ผ ๊ถŒํ•œ์„ ์ค„ ์ˆ˜ ์žˆ๊ฒŒ ์„ค์ •.
        />
            ))}
    </div>
</div>
</>
    );
};



export default Home;

App.js

import AppRouter from 'components/Router';
import {useState, useEffect} from "react";
import { auth } from "fbase";

 

function App() {
  
  const [init, setInit] = useState(false)
  const [isLoggedIn, setIsLoggedIn] = useState(auth.currentUser)
  const [userObj, setUserObj] = useState(null); // ๋กœ๊ทธ์ธ ์ •๋ณด๊ด€๋ฆฌ๋ฅผ ์œ„ํ•œ useState


  useEffect(() => {
    auth.onAuthStateChanged((user) =>{
      if(user){
        setIsLoggedIn(true);
        setUserObj(user);
      }else{
        setIsLoggedIn(false)
      }
      setInit(true);
    });
  }, []);

  return (
    <>
  {init ? <AppRouter isLoggedIn = {isLoggedIn} userObj={userObj} /> : "Initialzizing.."} 
  {/* userObj๋ฅผ AppRouter์„ ์ด์šฉํ•˜์—ฌ ๋ณด๋ƒ„ */}
  <footer>&copy; {new Date().getFullYear()} Nwitter</footer>

   </>
  )
}

export default App;

์˜ค๋Š˜ ๊ฒฐ๋ก 

์•Œ๋ฐ”ํ•˜๊ณ  ์ „๊ณต ์ค‘๊ฐ„๊ณ ์‚ฌ ๋Œ€์ฒด ๋ณด๊ณ ์„œ ์“ฐ๊ณ  ์šด๋™ํ•˜๋Š๋ผ ์›น ๊ณต๋ถ€๋ฅผ ๋งŽ์ด ๋ชปํ–ˆ๋‹ค..
๊ทธ๋ž˜๋„ ์งฌ๋‚ด์„œ ๊ณต๋ถ€ํ•˜๊ณ  ๋ธ”๋กœ๊ทธ๋„ ์“ด ๊ฑฐ์— ์˜์˜๋ฅผ ๋‘์ž..๐Ÿฅฒ

3๊ฐœ์˜ ๋Œ“๊ธ€

comment-user-thumbnail
2021๋…„ 10์›” 25์ผ

์šด๋™๋ณด๋‹จ ์›น์ด ๋จผ์ € ์•„๋‹Œ๊ฐ€์š” ? ใ… ใ…  ์„œ์šดํ•˜๋„ค์š”

1๊ฐœ์˜ ๋‹ต๊ธ€
comment-user-thumbnail
2021๋…„ 10์›” 31์ผ

์†Œํ”„ํŠธ์›จ์–ด ๋‘ํ†ต ใ…‹ใ…‹ใ…‹ใ…‹ใ…‹ ๐Ÿ‘๐Ÿ‘๐Ÿ‘

๋‹ต๊ธ€ ๋‹ฌ๊ธฐ