글 작성자: 택시 운전사
반응형

노마드 코더 트위터 클론 코딩

노마드 코더의 트위터 클론 코딩 강의를 듣고 정리한 강의노트입니다.


3 NWEETING

3.0 Form and Database Setup / 양식과 데이터베이스 설정

Firebase > Firestore Database

3.1 Nweeting! / 느위팅!

Firebase의 Cloude Database(Firestore Database)는 NoSQL database이기 때문에 유연하고 사용하기 쉽다. NoSQL database에는 다음과 같은 분류로 나뉜다.

  • Collection : 폴더와 같은 역할, 한 데이터베이스에는 여러개의 Collection이 존재할 수 있다.
  • Document : 폴더 안에 있는 문서와 같은 역할, 한 Collection에는 여러 개의 Document가 존재할 수 있다.

결론적으로 다음과 같은 포함관계를 갖게 된다.

Document ⊂ Collection ⊂ Database

Firebase v9.0으로 바뀌면서 firebaseConfig의 값이 달라졌다. 혹시 오류가 생긴다면 .env의 값이 현재 firebaseConfig에서 원하는 값과 같은 지 확인해보자.

// Home.jsx
import React, { useState } from 'react'
import { db } from 'fbase'
import { collection, addDoc, serverTimestamp } from '@firebase/firestore'

const Home = () => {
  const [nweet, setNweet] = useState('')

  const handleOnSubmit = async (e) => {
    e.preventDefault()

    const docRef = await addDoc(collection(db, 'nweets'), {
      nweet,
      createdAt: serverTimestamp(),
    })

    console.log('Document written with ID: ', docRef.id)

    setNweet('')
  }

  const handleOnChange = (e) => {
    const {
      target: { value },
    } = e
    setNweet(value)
  }

  return (
    <div>
      <form onSubmit={handleOnSubmit}>
        <input type="text" placeholder="What's on your mind?" maxLength={120} onChange={handleOnChange} value={nweet} />
        <input type="submit" value="Nweet" />
      </form>
    </div>
  )
}
export default Home

3.2 Getting the Nweets / 느윗 가져오기

// Home.jsx
import React, { useState, useEffect } from 'react'
import { db } from 'fbase'
import { collection, addDoc, getDocs, serverTimestamp } from '@firebase/firestore'

const Home = () => {
  const [nweet, setNweet] = useState('')
  const [nweets, setNweets] = useState([])

  useEffect(() => {
    const getNweets = async () => {
      const dbNweets = await getDocs(collection(db, 'nweets'))
      dbNweets.forEach((document) => {
        const nweetObject = {
          ...document.data(),
          id: document.id,
        }
        setNweets((prev) => [nweetObject, ...prev])
      })
      // setNweets(dbNweets.map((document) => document.data()))
    }
    getNweets()
  }, [])

  const handleOnSubmit = async (e) => {
    e.preventDefault()

    const docRef = await addDoc(collection(db, 'nweets'), {
      nweet,
      createdAt: serverTimestamp(),
    })

    console.log('Document written with ID: ', docRef.id)

    setNweet('')
  }

  const handleOnChange = (e) => {
    const {
      target: { value },
    } = e
    setNweet(value)
  }

  return (
    <div>
      <form onSubmit={handleOnSubmit}>
        <input type="text" placeholder="What's on your mind?" maxLength={120} onChange={handleOnChange} value={nweet} />
        <input type="submit" value="Nweet" />
      </form>
      <div>
        {nweets.map(({ id, nweet }) => (
          <div key={id}>
            <h4>{nweet}</h4>
          </div>
        ))}
      </div>
    </div>
  )
}
export default Home

3.3 Realtime Nweets / 실시간 느윗

현재 구현된 건 새로고침을 해야 다시 DB에 있는 정보를 가져와서 업데이트하는 방식, 하지만 FireStore Database는 Realtime Database이기 때문에 해당 이점을 살리기 위해 리얼 타임을 구현

// Home.jsx
import React, { useState, useEffect } from 'react'
import { db } from 'fbase'
import { collection, addDoc, query, onSnapshot, orderBy, serverTimestamp } from '@firebase/firestore'

const Home = ({ user }) => {
  const [nweet, setNweet] = useState('')
  const [nweets, setNweets] = useState([])

  useEffect(() => {
    // 실시간으로 데이터를 데이터베이스에서 가져오기

    const q = query(collection(db, 'nweets'), orderBy('createdAt', 'desc'))
    const unsubscribe = onSnapshot(q, (querySnapshot) => {
      const nextNweets = querySnapshot.docs.map((doc) => {
        return {
          id: doc.id,
          ...doc.data(),
        }
      })
      setNweets(nextNweets)
    })

    return () => {
      unsubscribe()
    }
  }, [])

  const handleOnSubmit = async (e) => {
    e.preventDefault()

    const docRef = await addDoc(collection(db, 'nweets'), {
      text: nweet,
      createdAt: serverTimestamp(),
      creatorId: user.uid,
    })

    console.log('Document written with ID: ', docRef.id)

    setNweet('')
  }

  const handleOnChange = (e) => {
    const {
      target: { value },
    } = e
    setNweet(value)
  }

  return (
    <div>
      <form onSubmit={handleOnSubmit}>
        <input type="text" placeholder="What's on your mind?" maxLength={120} onChange={handleOnChange} value={nweet} />
        <input type="submit" value="Nweet" />
      </form>
      <div>
        {nweets.map(({ id, text }) => (
          <div key={id}>
            <h4>{text}</h4>
          </div>
        ))}
      </div>
    </div>
  )
}
export default Home

3.4 Delete and Update / 삭제와 업데이트

// Nweet.jsx
import React, { useState } from 'react'
import { updateDoc, deleteDoc, doc } from '@firebase/firestore'
import { db } from 'fbase'

const Nweet = ({ nweet: { id, text }, isOwner }) => {
  const [editing, setEditing] = useState(false)
  const [newNweet, setNewNweet] = useState(text)

  const handleOnClickDelete = async () => {
    const ok = window.confirm('Are you sure you want to delete this nweet?')
    if (ok) {
      await deleteDoc(doc(db, `nweets/${id}`))
    }
  }

  const toggleEditing = () => {
    setEditing((prevEditing) => !prevEditing)
  }

  const handleOnChange = (e) => {
    const {
      target: { value },
    } = e
    setNewNweet(value)
  }

  const handleOnSubmit = async (e) => {
    e.preventDefault()
    await updateDoc(doc(db, `nweets/${id}`), {
      text: newNweet,
    })
    setEditing(false)
  }

  return (
    <div>
      {editing ? (
        <>
          <form onSubmit={handleOnSubmit}>
            <input type="text" placeholder="Edit your nweet" value={newNweet} required onChange={handleOnChange} />
            <input type="submit" value="Update Nweet" />
          </form>
          <button onClick={toggleEditing}>Cancel</button>
        </>
      ) : (
        <h4>{text}</h4>
      )}
      {isOwner && (
        <>
          <button onClick={handleOnClickDelete}>Delete Nweet</button>
          <button onClick={toggleEditing}>Edit Nweet</button>
        </>
      )}
    </div>
  )
}

export default Nweet
반응형