๐ŸŒŸ CRUD: Create

summereuna๐Ÿฅยท2022๋…„ 3์›” 31์ผ

๐ŸŒŸ Twinkle (React, Firebase)

๋ชฉ๋ก ๋ณด๊ธฐ
12/42

CRUD with firebase: โœ… Create(๋งŒ๋“ค๊ธฐ)-Tweeting


1. Cloud Firestore์˜ DB์˜ ์ œํ•œ ์‚ฌํ•ญ


  • SQL database
    • ์˜ค๋ž˜๋Œ
    • ๋งŽ์€ ๊ทœ์น™๊ณผ ๊ด€์Šต
    • ๊ทธ๋ ‡๋‹ค ๋ณด๋‹ˆ ์ข€ ๋” ์ž์œ ๋กœ์›€
      • ๊ด€๊ณ„ ๋งบ๊ณ  ์žˆ๋Š” ๋ฐ์ดํ„ฐ๊ฐ€ ์ž์ฃผ ๋ณ€๊ฒฝ๋  ๊ฒฝ์šฐ NoSQL์—์„œ๋Š” ์—ฌ๋Ÿฌ Collection์„ ์ˆ˜์ •ํ•ด์•ผ ํ•œ๋‹ค. ๋ช…ํ™•ํ•œ ์Šคํ‚ค๋งˆ๋ฅผ ๋ณด์žฅํ•  ๊ฒฝ์šฐ SQL์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.
  • NoSQL database
    • ์œ ์—ฐํ•˜๊ณ  ๊ทœ์น™์ด ๋งŽ์ด ์—†์–ด์„œ ์‚ฌ์šฉํ•˜๊ธฐ ์‰ฌ์›€
    • ๊ทœ์น™์ด ๋งŽ์ด ์—†๊ธฐ ๋•Œ๋ฌธ์— ์ œํ•œ๋˜๋Š” ๋ถ€๋ถ„์ด ์žˆ์Œ
      • ๋ถ„์‚ฐํ˜• ๊ตฌ์กฐ๋กœ ์—ฌ๋Ÿฌ ์„œ๋ฒ„์— ๋ฐ์ดํ„ฐ๋ฅผ ๋ถ„์‚ฐ ์ €์žฅํ•˜์—ฌ ํŠน์ • ์„œ๋ฒ„์— ์žฅ์•  ๋ฐœ์ƒํ•ด๋„ ์„œ๋น„์Šค๊ฐ€ ์ค‘์ง€๋˜์ง€ ์•Š๊ฒŒ ํ•œ๋‹ค.
      • ๋ช…ํ™•ํ•˜์ง€ ์•Š์€ ํ…Œ์ด๋ธ” ์Šคํ‚ค๋งˆ๋ฅผ ๊ฐ€์ง„๋‹ค. ์ •ํ™•ํ•œ ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ๋ฅผ ์•Œ ์ˆ˜ ์—†๊ฑฐ๋‚˜ ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ๊ฐ€ ๋ณ€๊ฒฝ, ํ™•์žฅ ๋  ๊ฒฝ์šฐ NoSQL์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.
      • ํŽ˜์ด์Šค๋ถ, ํŠธ์œ„ํ„ฐ ๊ฐ™์€ ์†Œ์…œ ๋ฏธ๋””์–ด์˜ ๊ฒฝ์šฐ ๊ฒŒ์‹œ๊ธ€์„ ์ €์žฅํ•˜๋Š”๋ฐ NoSQL database๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

Cloud Firestore์˜ DB๋Š” NoSQL database์ด๋‹ค.
๋งŽ์€ ๊ฒƒ์„ ํ”„๋กœ๊ทธ๋žจํ•˜์ง€ ์•Š์•„๋„ ๋˜๊ณ  ์œ ์—ฐํ•˜๋‹ค.
๊ทธ๋ ‡๋‹ค๋ณด๋‹ˆ ๋ช‡ ๊ฐ€์ง€ ์ œํ•œ ์‚ฌํ•ญ์ด ์žˆ๋‹ค.

NoSQL database์˜ ํŠน์ง•

collection(๊ธฐ๋ณธ์ ์œผ๋กœ ํด๋” ๊ฐ™์€ ๊ฐœ๋…), document(์ปดํ“จํ„ฐ์— ์žˆ๋Š” ๋ฌธ์„œ ๊ฐ™์€ ๊ฐœ๋…)๋ฅผ ๊ฐ€์ง„๋‹ค.
๋”ฐ๋ผ์„œ ํ•˜๋‚˜์˜ Database๋Š” collection๋“ค์„ ๊ฐ€์ง€๊ณ  ์žˆ๊ณ , ๊ฐ๊ฐ์˜ collection์€ document๋“ค์„ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค.

๋ชฝ๊ณ ๋””๋น„๊ฐ€ ์ƒ๊ฐ๋‚˜๋Š” ๊ตฌ๋จผ! ๋ชฝ๊ณ ๋””๋น„๋Š” document db ์˜€์Œ ใ…‡ใ…‡!


2. Cloud Firestore์˜ admin panel ์—์„œ ์ปฌ๋ ‰์…˜๊ณผ ๋‹คํ๋จผํŠธ ๋งŒ๋“ค์–ด ๋ณด๊ธฐ


  1. Cloud Firestore์˜ admin panel ์—์„œ + ์ปฌ๋ ‰์…˜ ์‹œ์ž‘์„ ํด๋ฆญํ•˜์—ฌ ์ปฌ๋ ‰์…˜์„ ๋งŒ๋“ค์–ด ๋ณด์ž.

  2. tweets ์ปฌ๋ ‰์…˜์„ ๋งŒ๋“ ๋‹ค.

  3. ๋‹คํ๋จผํŠธ ID๋ฅผ ์ •ํ•˜์ž. ์ž๋™ ID๋ฅผ ๋ˆ„๋ฅด๋ฉด ์ž๋™์œผ๋กœ ์ •ํ•ด์ค€๋‹ค.

  4. ์ด๋ ‡๊ฒŒ ์–ด๋“œ๋ฏผ ํŒจ๋„์—์„œ ์ปฌ๋ ‰์…˜๊ณผ ์ปฌ๋ ‰์…˜์˜ ๋‹คํ๋จผํŠธ๋ฅผ ์‰ฝ๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.


3. ์ฝ”๋“œ๋กœ ์ปฌ๋ ‰์…˜, ๋‹คํ๋จผํŠธ ์ƒ์„ฑํ•˜๊ธฐ


์ด์ œ ์–ด๋“œ๋ฏผ ํŒจ๋„์—์„œ ์‚ฌ์šฉํ•œ ๊ธฐ๋Šฅ์„ ๋˜‘๊ฐ™์ด ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜์—ฌ ๊ตฌํ˜„ํ•ด๋ณด์ž. ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜์—ฌ ์ปฌ๋ ‰์…˜์„ ์ƒ์„ฑํ•˜๊ณ  ๋‹คํ๋จผํŠธ์™€ ๋ฐ์ดํ„ฐ๋ฅผ ์ƒ์„ฑํ•ด ๋ณด์ž.

  1. ๋จผ์ € ๐Ÿ“fbase.js์— firestore๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด firebase/firestore์—์„œ getFirestore๋ฅผ ๊ฐ€์ ธ์˜จ๋‹ค.

  2. ๊ทธ๋ฆฌ๊ณ  dbService๋ผ๋Š” ๋ณ€์ˆ˜์ด๋ฆ„์œผ๋กœ getFirestore()๋ฅผ ๋‚ด๋ณด๋‚ธ๋‹ค.

//โœ… ํŒŒ์ด์–ด๋ฒ ์ด์Šค์—์„œ ๋ฐ์ดํ„ฐ ๋ฒ ์ด์Šค ๊ฐ€์ ธ์˜ค๊ธฐ
import { getFirestore } from "firebase/firestore";

//โœ… ๋””๋น„ ์„œ๋น„์Šค ๋‚ด๋ณด๋‚ด๊ธฐ
export const dbService = getFirestore();

๐Ÿ“ fbase.js

//โœ… Firebase Web v.9
//์ฐธ๊ณ : https://firebase.google.com/docs/web/modular-upgrade#refactor_to_the_modular_style
//Follow this pattern to import other Firebase services
//import { } from 'firebase/<service>';

//์•ฑ ์ดˆ๊ธฐํ™” ๊ฐ€์ ธ์˜ค๊ธฐ
import { initializeApp } from "firebase/app";
//ํŒŒ์ด์–ด๋ฒ ์ด์Šค์—์„œ ์ธ์ฆ ์‹œ์Šคํ…œ ๊ฐ€์ ธ์˜ค๊ธฐ
import { getAuth } from "firebase/auth";
//โœ… ํŒŒ์ด์–ด๋ฒ ์ด์Šค์—์„œ ๋ฐ์ดํ„ฐ ๋ฒ ์ด์Šค ๊ฐ€์ ธ์˜ค๊ธฐ
import { getFirestore } from "firebase/firestore";

// Your web app's Firebase configuration
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 app = initializeApp(firebaseConfig);

//์–ด์Šค ์„œ๋น„์Šค ๋‚ด๋ณด๋‚ด๊ธฐ
//๊ตณ์ด firebase ์ „์ฒด ๋‹ค ์•ˆ๋‚ด๋ณด๋‚ด๊ณ  authService๋งŒ exportํ•  ์ˆ˜ ์žˆ๋‹ค.
//authService ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ์„ ๋•Œ ๋งˆ๋‹ค getAuth(app) ํ˜ธ์ถœํ•ด์•ผ ํ•˜๋‹ˆ๊นŒ app.js์—์„œ ๋‹จ ํ•œ ๋ฒˆ๋งŒ ํ˜ธ์ถœํ•˜๊ณ  export ์‹œํ‚ค๋ฉด ๋œ๋‹ค.
export const authService = getAuth(app);

//โœ… ๋””๋น„ ์„œ๋น„์Šค ๋‚ด๋ณด๋‚ด๊ธฐ
export const dbService = getFirestore();

  1. routes/Home.js์— fbase์—์„œ dbService๋ฅผ ๊ฐ€์ ธ์˜จ๋‹ค.
    //dbService ๊ฐ€์ ธ์˜ค๊ธฐ
    import { dbService } from "fbase";
  1. ํŠธ์œ—ํ•˜๊ธฐ๋ฅผ ๋ˆ„๋ฅด๋ฉด, ์ฆ‰ submitํ•˜๋ฉด ํŠธ์œ™ํด์•ฑ์˜ ํŒŒ์ด์–ด์Šคํ† ์–ด์— ์ƒˆ๋กœ์šด document๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋„๋ก ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜์ž.
  • firebase/firestore์—์„œ collection, addDoc, serverTimestamp๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด ๊ฐ€์ ธ์˜จ๋‹ค.

    import { collection, addDoc, serverTimestamp } from "firebase/firestore";
  • onSubmitํ•จ์ˆ˜ ์•ˆ์— ๋‹คํ๋จผํŠธ์— ์ƒˆ๋กœ์šด ๋ฐ์ดํ„ฐ๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•œ๋‹ค.

Cloud Firestore๋Š” Collection์— ์ €์žฅ๋œ Document์— data๋ฅผ ์ €์žฅํ•œ๋‹ค.

  • Cloud Firestore๋Š” ์ฒ˜์Œ์œผ๋กœ Document์— data๋ฅผ ์ถ”๊ฐ€ํ•  ๋•Œ ์•”์‹œ์ ์œผ๋กœ Collection๊ณผ Document๋ฅผ ๋งŒ๋“ ๋‹ค.
  • Collection์ด๋‚˜ Document๋ฅผ ๋ช…์‹œ์ ์œผ๋กœ ๋งŒ๋“ค ํ•„์š”๋Š” ์—†๋‹ค.
    • ๋‹ค์Œ ์˜ˆ์ œ ์ฝ”๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ƒˆ Collection๊ณผ Document๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.
//Web v.9
import { collection, addDoc } from "firebase/firestore"; 
//
try {
  const docRef = await addDoc(collection(db, "์ปฌ๋ ‰์…˜ ์ด๋ฆ„"), {
    //data๋Š” `key: value` ์Œ์œผ๋กœ ์ •๋ณด๋ฅผ ์ ์œผ๋ฉด ๋œ๋‹ค.
    first: "Ada",
    last: "Lovelace",
    born: 1815
  });
  console.log("Document written with ID: ", docRef.id);
} catch (e) {
  console.error("Error adding document: ", e);
}
  • ๋˜ํ•œ ๊ฐ™์€ Collection์— ๋‹ค๋ฅธ Document๋„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ์œ„์˜ Document์—๋Š” ์—†๋Š” ํ‚ค(key)์™€ ๊ฐ’(value)์˜ ์Œ์„ ํฌํ•จํ•ด๋„ ๋œ๋‹ค. ์ฆ‰, Collection์˜ Document์—๋Š” ์„œ๋กœ ๋‹ค๋ฅธ ์ •๋ณด ์„ธํŠธ๊ฐ€ ํฌํ•จ๋˜๋„ ๋œ๋‹ค. (์ด ๋ง์€ ์Šคํ‚ค๋งˆ๊ฐ€ ๋ช…ํ™•ํ•˜์ง€ ์•Š๋‹ค๋Š” ๋œป์ธ ๋“ฏ ใ…‡ใ…‡! ํŒŒ์ด์–ด๋ฒ ์ด์Šค๋Š” ๋…ธ์—์Šคํ์—˜!)
//Web v.9
import { collection, addDoc } from "firebase/firestore"; 
//
try {
  const docRef = await addDoc(collection(db, "์ปฌ๋ ‰์…˜ ์ด๋ฆ„"), {
    first: "Alan",
    //์ด๋Ÿฐ ์‹์œผ๋กœ ์œ„์˜ ๋‹คํ๋จผํŠธ์—๋Š” ์—†๋Š” ์ •๋ณด ์„ธํŠธ๋ฅผ ํฌํ•จํ•  ์ˆ˜ ์žˆ์Œ!
    middle: "Mathison",
    last: "Turing",
    born: 1912
  });
  console.log("Document written with ID: ", docRef.id);
} catch (e) {
  console.error("Error adding document: ", e);
}

๐Ÿ‘‰ ์ฐธ๊ณ  ๋ฌธ์„œ

์ฝ”๋“œ

addDoc(collection(db, "์ปฌ๋ ‰์…˜์ด๋ฆ„"), { key: value });์„ ์‚ฌ์šฉํ•˜์—ฌ collection์˜ Document์— data๋ฅผ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋‹ค.

  • ์œ„์˜ ์„ค๋ช… ์ฒ˜๋Ÿผ Document์— data๋ฅผ ์ถ”๊ฐ€ํ•  ๋•Œ ์•”์‹œ์ ์œผ๋กœ Collection๊ณผ Document๊ฐ€ ์ฒ˜์Œ ๋งŒ๋“ค์–ด ์ง€๊ธฐ ๋•Œ๋ฌธ์— ์ด ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค.
  • ์ด ๋ฉ”์„œ๋“œ๋Š” Document์˜ ID๊ฐ’์„ ๋ฌด์ž‘์œ„๋กœ ์ •ํ•œ๋‹ค.
    • ๋‹คํ๋จผํŠธ ID๊ฐ’์€ ๊ตณ์ด ํ•„์š” ์—†์„๊ฒƒ ๊ฐ™๊ธฐ ๋•Œ๋ฌธ์— ๊ฑ ์ด๊ฑธ๋กœ ๊ฐ€๋ฉด ๋ ๋“ฏ!
      const Home = () => {
      //ํ™ˆ์—์„œ ํŠธ์œ— ๋‚ด์šฉ ์ž‘์„ฑํ•˜๋Š” ํผ
      const [tweet, setTweet] = useState("");
      
      const onSubmit = async (event) => {
       event.preventDefault();
       //ํŠธ์œ—ํ•˜๊ธฐ ๋ˆ„๋ฅด๋ฉด ์ƒˆ๋กœ์šด document ์ƒ์„ฑํ•˜๊ธฐ
       try {
         const docRef = await addDoc(collection(dbService, "tweets"), {
           tweet, // tweet(๋‹คํ๋จผํŠธ์˜ key): tweet(value๋กœ tweet state ๊ฐ’)
           createdAt: serverTimestamp(), //Date.now(),๋กœ ํ•ด๋„ ๋˜์ง€๋งŒ ์ด์™• ์žˆ๋Š”๊ฑฐ ํ•จ ์จ๋ณด์ž(ํƒ€์ž„์กด ๋™๋ถ์•„3 = ์„œ์šธ๋กœ ์„ค์ •๋˜์–ด ์žˆ์Œ)
         });
         console.log("Document written with ID: ", docRef.id);
       } catch (error) {
         console.error("Error adding document: ", error);
       }
       //state ๋น„์›Œ์„œ form ๋น„์šฐ๊ธฐ
       setTweet("");
      };

๐Ÿ“routes/Home.js

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

const Home = () => {
  //ํ™ˆ์—์„œ ํŠธ์œ— ๋‚ด์šฉ ์ž‘์„ฑํ•˜๋Š” ํผ
  const [tweet, setTweet] = useState("");
  
  const onSubmit = async (event) => {
    event.preventDefault();
    //ํŠธ์œ—ํ•˜๊ธฐ ๋ˆ„๋ฅด๋ฉด ์ƒˆ๋กœ์šด document ์ƒ์„ฑํ•˜๊ธฐ
    try {
      const docRef = await addDoc(collection(dbService, "tweets"), {
        tweet, // tweet(๋‹คํ๋จผํŠธ์˜ key): tweet(value๋กœ tweet state ๊ฐ’)
        createdAt: serverTimestamp(), //Date.now(),๋กœ ํ•ด๋„ ๋˜์ง€๋งŒ ์ด์™• ์žˆ๋Š”๊ฑฐ ํ•จ ์จ๋ณด์ž(ํƒ€์ž„์กด ๋™๋ถ์•„3 = ์„œ์šธ๋กœ ์„ค์ •๋˜์–ด ์žˆ์Œ)
      });
      console.log("Document written with ID: ", docRef.id);
    } catch (error) {
      console.error("Error adding document: ", error);
    }
    //state ๋น„์›Œ์„œ form ๋น„์šฐ๊ธฐ
    setTweet("");
  };

  const onChange = (event) => {
    const {
      target: { value },
    } = event;
    setTweet(value);
    //console.log(tweet);
  };

  return (
    <div>
      <form onSubmit={onSubmit}>
        <input
          type="text"
          placeholder="๋ฌด์Šจ ์ผ์ด ์ผ์–ด๋‚˜๊ณ  ์žˆ๋‚˜์š”?"
          maxLength={120}
          value={tweet}
          onChange={onChange}
        />
        <input type="submit" value="ํŠธ์œ—ํ•˜๊ธฐ" />
      </form>
    </div>
  );
};

export default Home;
profile
Always have hope๐Ÿ€ & constant passion๐Ÿ”ฅ

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