소원을 들어주는 올라프 만들기 2

수딩·2022년 9월 16일
2
post-thumbnail

개요

이전에 만들었던 올라프를 활용하여 나만의 소원을 적는 메모앱을 만들면 어떨까? 하는 마음으로 리액트와 파이어베이스를 사용하여 만들어본 토이 프로젝트이다.

이 프로젝트에서는 리액트와 파이어 베이스를 사용하였다.
리액트는 워낙 편리한 라이브러리이기도 하고, 리액트를 활용한 토이프로젝트를 진행해보고 싶었기에 사용하였다.

파이어 베이스는 파이어 베이스의 DB를 이용해 데이터를 저장하고 불러오는 기능을 구현할 수 있다. 백엔드를 구축할 수 없는 토이 프로젝트에서 사용하기에 찰떡이라 사용하였다.

나는 로그인, 로그아웃, 소원작성, 소원삭제 기능이 있는 소원앱을 만들 계획이다.

프로젝트 시작하기

터미널에 아래 코드를 입력하여 리액트 프로젝트 시작!

npx create-react-app 

그리고 파이어베이스에 앱을 등록하고

firebase를 설치!
https://firebase.google.com/ <-파이어베이스 주소

npm install firebase

src 폴더에 firebase-> config.js 라는 파일을 생성해서 파이어베이스에서 제공한 SDK설정 script 코드를 내 파일에 붙여 놓는다.

import { initializeApp } from "firebase/app";

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,
};

// firebase 초기화
const app = initializeApp(firebaseConfig);
// firestore 초기화 ->  훗날 데이터 저장을 위해
const appFireStore = getFirestore(app);

export default app;

process.env.REACT_APP_API_KEY 이건 뭐냐면
인증키는 공개되면 안되는 아이들이기 때문에(사용자가 누군지 알려주는 정보) 환경변수로 만들어 준 것 이렇게 .env 파일을 따로 만들어서 보관 해주면 된다.
그리고 이 .env 파일은 .gitignore 파일에 넣어줌!

자 이제,
index.js 파일에 import를 해줘야 한다.

import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import app from './fBase.js'

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

라우팅 처리하기

나는 로그인페이지, 회원가입페이지, 메인페이지, 소원작성페이지 총 4가지 페이지를 만들어 줬기 때문에 라우트를 4개로 처리했다.

라우트 사용 위해 react-router-dom 설치, Routes 는 V6 사용

npm install react-router-dom 
<BrowserRouter>
  <Nav />
  <Routes>
    <Route path="/" element={<Home />}></Route>
    <Route path="/login" element={<Login />}></Route>
    <Route path="/signup" element={<Signup />}></Route>
    <Route path="/wish" element={<Wish />}></Route>
  </Routes>
</BrowserRouter>

Authentication 구현

파이어베이스에서 어떤 인증 서비스를 사용할지 고를 수가 있는데 나는 이메일, 비밀번호 인증을 사용하여 로그인 하는 방식을 선택하였다.

Authentication에서 제공하는 여러 기능을 이용하기 위해 config.js 파일에 관련 코드를 추가한다.

import { getAuth } from "firebase/auth";

// 인증 초기화
const appAuth = getAuth();

export { appFireStore, appAuth }

회원가입 구현과 context 관리

로그인, 회원가입 폼을 작성하고 useLogin, useSignup hooks를 만들었다.
Custom hook을 따로 만들어준 이유는 다른 컴포넌트에서도 재사용이 가능하도록 해주기 위함이다.

파이어베이스에서는 로그인, 회원가입, 로그아웃을 위한 함수를 제공한다.
-로그인
signInWithEmailAndPassword

import { getAuth, signInWithEmailAndPassword } from "firebase/auth";

const auth = getAuth();
signInWithEmailAndPassword(auth, email, password)
  .then((userCredential) => {
    // Signed in
    const user = userCredential.user;
    // ...
  })
  .catch((error) => {
    const errorCode = error.code;
    const errorMessage = error.message;
  });

-회원가입
createUserWithEmailAndPassword

import { getAuth, createUserWithEmailAndPassword } from "firebase/auth";

const auth = getAuth();
createUserWithEmailAndPassword(auth, email, password)
  .then((userCredential) => {
    // Signed in
    const user = userCredential.user;
    // ...
  })
  .catch((error) => {
    const errorCode = error.code;
    const errorMessage = error.message;
    // ..
  });

-로그아웃
signOut

import { getAuth, signOut } from "firebase/auth";

const auth = getAuth();
signOut(auth).then(() => {
  // Sign-out successful.
}).catch((error) => {
  // An error happened.
});

이 함수들을 이용하여 커스텀 훅을 만들었다.

회원가입 구현

useSignup custom hook

import { useState } from 'react'
import { appAuth } from '../firebase/config'
import { createUserWithEmailAndPassword, updateProfile } from 'firebase/auth'
//파이어베이스에서 제공하는 함수 import 해주기 

export const useSignup = () => {

    const [error, setError] = useState(null); // 에러 정보 
    const [isPending, setIsPending] = useState(false);  // 서버와 통신중인 상태 

   // email, password, displayName 세가지 매개변수를 가짐
    const signup = (email, password, displayName) => {
        setError(null); // 아직 에러가 없으니 null 
        setIsPending(true); // 통신중이므로 true

        createUserWithEmailAndPassword(appAuth, email, password) //파이어베이스 제공함수
            .then((userCredential) => {
                // Signed in
                const user = userCredential.user;
                console.log(user);
                if (!user) {
                    throw new Error('회원가입에 실패했습니다.');
                }

                // 회원가입이 완료되면 유저 정보에 닉네임을 업데이트
                updateProfile(appAuth.currentUser, { displayName })
                    .then(() => {
                        setError(null);
                        setIsPending(false);
                    }).catch((err) => {
                        setError(err.message);
                        setIsPending(false)
                        console.log(err.message);
                    });
            })
            .catch((err) => {
                setError(err.message);
                setIsPending(false);
                console.log(err.message);
            });
    }

    return { error, isPending, signup }
}

처음에 nickName 으로 변수명을 설정해주었다가 오류가 나고 잘 작동이 되지 않았다. 알고보니 displayName은 파이어베이스에서 유저 정보에 저장 할 수 있는 속성중 하나라서 다른 변수명을 사용하면 안된다고 한다 ..

Signup.jsx 에 적용

import { useState } from "react";
import { useSignup } from "../../hooks/useSignup";
import styles from "./Signup.module.css";

function Signup() {
    const [email, setEmail] = useState("");
    const [password, setPassword] = useState("");
    const [displayName, setDisplayName] = useState("");

  // 만들어준 커스텀 훅을 이용하기 위해 작성
    const { error, isPending, signup } = useSignup(); 
//회원가입 폼을 제출하면 signup 훅이 작동! 
    const handleSubmit = (e) => {
        e.preventDefault();
        signup(email, password, displayName);
    };

    return (
        <form className={styles.signup_form} onSubmit={handleSubmit}>
			{/* 생략  */}
            {!isPending && (
                <button type="submit" className={styles.btn}>
                    START
                </button>
            )}
            {isPending && <strong className={styles.loding_text}>Loading...</strong>}
            {error && <strong className={styles.error_text}>{error}</strong>}
        </form>
    );
}

export default Signup;

만들어준 signup 커스텀 훅을 적용해주었다. 그리고 pending, error 상태일때 보여줄 화면도 삼항연산자를 이용하여 작성해주었다.

회원가입을 해보자 !

가입 후 파이어베이스 콘솔에서 확인해보니 가입한 유저정보가 들어와 있음을 볼 수 있다 !

AuthContext.jsx

파이어베이스는 회원가입을 하면 저절로 로그인까지 이뤄진다.

이제 로그인이 된 상태일 때와 아닐 때의 화면을 다르게 만들어 주고 싶은데 ?
=> 유저 정보를 Context 로 관리해주자 !
Context 는 리액트 컴포넌트 트리 안에서 데이터를 전역으로 사용할 수 있도록 해준다. 그래서 트리단계마다 props를 넘겨줄 필요 없이 어디에서나 꺼내 쓸 수 있게끔 Context 로 관리해줄 것 !

src 폴더에 context 폴더를 생성하고 인증과 관련된 정보를 담을 AuthContext.jsx 파일을 만들어서 관리

import { useReducer, createContext, useEffect } from "react";
import { onAuthStateChanged } from "firebase/auth";
import { appAuth } from "../firebase/config";

//context 객체 생성
const AuthContext = createContext();

//리듀서 함수로 유저 정보 관리 - 객체화 데이터는 리듀서 이용
const authReducer = (state, action) => {
    switch (action.type) {
        case "login":
            return { ...state, user: action.payload }; //기존의 유저정보에 새로운 유저 상태병합
        case "logout":
            return { ...state, user: null };
        case "isAuthReady":
            return { ...state, user: action.payload, isAuthReady: true };
        default:
            return state;
    }
};

//context 를 구독할 컴포넌트의 묶음 범위를 설정
const AuthContextProvider = ({ children }) => {
    // 유저정보 관리 
    //useReducer 매개변수 : 리듀더 함수, 관리할 유저정보의 초기화
    const [state, dispatch] = useReducer(authReducer, {
        user: null,
        isAuthReady: false,
    });

    useEffect(() => {
        const unsubscribe = onAuthStateChanged(appAuth, (user) => {
            dispatch({ type: "isAuthReady", payload: user });
        });
        return unsubscribe;
    }, []);

  //유저 정보를 value 값으로 불러옴
    return <AuthContext.Provider value={{ ...state, dispatch }}>{children}</AuthContext.Provider>;
};
export { AuthContext, AuthContextProvider };

useReducer

useState의 대체 함수이다. 보통 숫자형이나 문자열 같은 간단한 형태의 데이터는 useState를 이용하지만 객체와 같이 복잡한 형태의 데이터를 다룰 때 Reducer을 많이 사용한다!
형태:
const [관리할 값, dispatch 함수] = useReducer(리듀서 함수, 관리할 값의 초기화)
dispatch 함수: 리듀서 함수를 호출하는 역할
형태:
dispatch({ type: 'login', payload: user })
전달하는 인자: action
action에는 type과 전달할 데이터인 payload 가 있다.

그리고 이걸
index.js 에서 를 Context 로 감싸 하위에 있는 컴포넌트가 컨텍스트 정보에 접근할 수 있도록 작성해줌

import { AuthContextProvider } from './context/AuthContext';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <AuthContextProvider>
      <App />
    </AuthContextProvider>
  </React.StrictMode>
);

이 다음 단계로,
인증 context를 쉽게 사용할 수 있도록 훅을 만들어 주었다.

import { useContext } from "react";
import { AuthContext } from "../context/AuthContext";

export const useAuthContext = () => {
    const context = useContext(AuthContext);

    return context; //state(유저정보) 와 dispatch 함수가 들어있음
};

useAuthContext를 통해 업데이트하면 이제 유저정보를 어디서든 사용할 수가 있다.
그렇게 해주기 위해서는 useSignup.jsx 훅에 아래 코드를 추가해준다.

// 유저정보를 전역에서 활용할 수 있도록 dispatch 함수를 통해 회원 정보의 상태 업데이트
const { dispatch } = useAuthContext();

…
…

// 프로필을 업데이트하는 함수에 dispatch 함수를 실행하여 만들었던 authReducer 함수를 호출
updateProfile(appAuth.currentUser, { displayName })
.then(() => {
// action으로 전달될 인자 
    dispatch({ type: 'login', payload: user }); //유저 업데이트
    setError(null);user
    setIsPending(false);
}).catch((err) => {
    setError(err.message);
    setIsPending(false)
    console.log(err.message);
});

정말 복잡하고 어려운 과정이었다...
이제 제대로 작동이 되는지 확인해보자
AuthContext 에 콘솔을 찍어서 회원가입 진행을 해보니

짠 유저 정보가 잘 들어와 있음을 볼 수 있다.

로그인 기능도 회원가입과 비슷하게 구현해주면 됨!

useLogin.jsx hook

import { useState } from "react";
import { appAuth } from "../firebase/config";
import { signInWithEmailAndPassword } from "firebase/auth";
import { useAuthContext } from "./useAuthContext";

export const useLogin = () => {
    const [error, setError] = useState(null); //에러 정보를 저장한다. 
    const [isPending, setIsPending] = useState(false); //서버와 통신중인 상태를 저장한다. 
    const { dispatch } = useAuthContext();

    const login = (email, password) => {
        setError(null); // 아직 에러가 없기 때무에 null로 설정
        setIsPending(true); //서버와 통신중이기 때문에 true로 설정

        signInWithEmailAndPassword(appAuth, email, password)
            .then((userCredential) => {
                // Loged in
                const user = userCredential.user;
                dispatch({ type: "login", payload: user });
                setError(null);
                setIsPending(false);

                if (!user) {
                    throw new Error("회원가입에 실패했습니다.");
                }
            })
            .catch((err) => {
                setError(err.message);
                setIsPending(false);
            });
    };

    return { error, isPending, login };
};

useLogin 커스텀훅을 만들어주고
Login.jsx 에서 이걸 사용할 수 있도록 코드를 추가해주면 된당.

다 작성하면 아까 회원가입 해줬었던
olaf@gmail.com 계정으로 로그인이 가능해진다!


이메일 혹은 비밀번호가 틀렸을 경우의 에러처리까지 해주면 완료!

유저 여부에 따라 다른 화면 보여주기

개인적으로 개발하면서 가장 신기하고 재미있는 부분이 유저에 따라 다른 화면을 보여주는 것 이다. 로그인 했을때와 안했을 때의 상태를 다르게 구현해보자 !

우선 UI 구성은 이러하다.

  • 로그인 하지 않은 유저 홈화면
  • 로그인 한 유저 홈화면
  • 로그인 한 유저만 접근이 가능한 Wish 페이지

이를 구현하기 위해서는
만들어준

import { useAuthContext } from '../hooks/useAuthContext';

const { user } = useAuthContext();

을 임포트해서 user을 받아온다.

{!user && (
  <>
    <li>
        <Link to="/login">LOGIN</Link>
    </li>
    <li>
       <Link to="/signup">SIGNUP</Link>
    </li>
  </>
  )}
{user && (
  <>
    <li>
       <Link to="/" onClick={logout}>
        Logout
       </Link>
    </li>
  </>
)}

그리고 !user && , user && 은 !user 이 true 일 때.
즉, 전자는 유저가 없는게 맞을 때, 후자는 유저가 있는게 맞을 때 나오는 요소가 된다!

FireStore 사용하기

useFirestore hook 생성

Firebase 홈페이지에서 database 페이지로 이동 후 테스트 모드로 데이터베이스를 하나 만들어 준다.
그리고 코드로 돌아와서 firestore 전용 훅을 만든다.

isPending, Error + document 와 sucess 까지 조금 많은 애들을 관리해줘야 하기 때문에
useReducer로 작성해줄것!

//관리할 애들 객체 생성, 초기화
const initState = {
    document: null, //파이어스토어에 document의 생성을 요청하면 생성한 document를 반환 
    isPending: false, //통신중인지 아닌지 상태
    error: null,
    success: false //요청에 대한 응답의 성공 유무
}

// 전달 받는 action에 따른 state 업데이트를 위한 함수
const storeReducer = (state, action) => {
    switch (action.type) {

        default:
            return state
    }
}

파이어 스토어에는 도큐먼트와 컬렉션이 있다.
문서(document)는 데이터를 객체 형식으로 저장하는데 이 저장 공간을 말하고,
컬렉션은 여러 문서 저장하는 문서의 컨테이너를 말한다. (컬렉션은 반드시 필요)

colRef : 컬렉션의 참조 요구
firestore에서 collection method 불러오기
collection의 인자: (config에서 파베초기화 했던 appFireStore, 컬렉션의 이름)
컬렉션을 만들지 않았어도 이걸 사용하면 파이어베이스에서 자동으로 컬렉션을 생성해준다!

// 저장할 컬렉션을 인자로 저장
export const useFirestore = (transaction) => {
	//[관리할 데이터 이름, 디스페치]
    const [response, dispatch] = useReducer(storeReducer, initState);

    const colRef = collection(appFireStore, transaction);

    //컬렉션에 문서 추가
    const addDocument = async (doc) => {
        dispatch({ type: "isPending" });
	//시간순으로 정렬위해 timestamp를 불러와서 createdTime을 만들어준다.
        try {
            const createdTime = timeStamp.fromDate(new Date()); 
            const docRef = await addDoc(colRef, { ...doc, createdTime });
            dispatch({ type: "addDoc", payload: docRef });
        } catch (error) {
            dispatch({ type: "error", payload: error.message });
        }
    };

    return { addDocument, response };
};

디스패치에 넣어준 타입을 적어준다.

const storeReducer = (state, action) => {
    switch (action.type) {
        case "isPending":
            return {
                isPending: true,
                document: null,
                success: false,
                error: null,
            };
        case "addDoc":
            return {
                isPending: false,
                document: action.payload,
                success: true,
                error: null,
            };
        case "error":
            return {
                isPending: false,
                document: null,
                success: false,
                error: action.payload,
            };
        default:
            return state;
    }
};

useFirestore 훅 사용하기

wishForm.jsx 에 적용하기

소원 작성 form 을 submit 하면 store에 전달되게끔 해보자.

function WishForm({ uid }) { 
  //userid를 props로 받기 -> Wish.jsx에 useAuthContext로 받아오기
    const { addDocument, response } = useFirestore("wish"); 
  //useFirestore에서 함수들을 받아오고
 //addDocument에 ({ uid, title, text }) 로 받아오기 ! 
    const handleSubmit = (e) => {
        e.preventDefault();
        addDocument({ uid, title, text }); 
    };

그럼 소원을 작성하고 확인을 해보면!

뭔가가 잘 작동한 듯한 콘솔이 찍혀있다!
파이어베이스에 들어가서 스토어를 확인해보자

굳 !!!!!
원했던 uid , title, text, createdTime 까지 잘 저장되어 있음을 볼 수 있다.

위에서 통신이 잘 된 것을 확인할 수 있다!
통신이 잘 되면 인풋값을 초기화 해주자~

   //통신 완료되면 인풋 값 초기화
    useEffect(() => {
        if (response.success) {
            setTitle("");
            setText("");
        }
    }, [response.success]);

input 에 value 값을 넣어주는 것 잊지말자 !

<input
	className={styles.wish_tit_text}
	id="title"
	type="text"
	maxLength="50"
	required
	onChange={handleData}
	value={title}
/>

같은 방법으로 text input 로 작성.

저장한 데이터 불러오기

useCollection hook 생성

firestore에서 제공하는 onSnapshot 함수를 사용할 것이다.
onSnapshot은 가장 최신의 컬렉션의 내용을 반환시켜준다.
그리고 이걸 snapshot 인자로 받아온다!
collection에 변화가 생길때마다 실행하도록 useEffect 함수로 불러온다.
때문에 항상 최신의 컬랙션 상태를 반환 받을 수 있다.

import { collection, onSnapshot} from "firebase/firestore";

function useCollection(transaction) {

    useEffect(() => {
        onSnapshot(collection(appFireStore, transaction),
            (snapshot) => {
                //snapshot 에 doc이 배열 형태로 저장되어 있음 .
                let result = [];
                snapshot.docs.forEach((doc) => {
                    result.push({ ...doc.data(), id: doc.id });
                });
//각각의 도큐먼트의 문서를 가져오기 위해 데이터 메서드를 실행(전개구문으로 데이터 함수의 반환값을 객체에 나열)
//id도 추가 
        })
    })
}

여기까지 했으면 state를 통해 컬렉션의 도큐먼트, 에러상태를 관리해주자 .

근데 여기서
onSnapshot 함수를 실행시킨다는 것 = 파이어스토어와 통신하게 되는 것 = 통신 채널을 열어둔 상태로 두게 되는 것이다.
데이터를 또 수신하기 위해 대기상태가 되는 것인데,
이걸 중단시켜주기 위해 스냅샷은 자동으로 unsubscribe 클린업 함수를 반환해준다.

function useCollection(transaction, myQuery) {
    const [documents, setDocuments] = useState(null);
    const [error, setError] = useState(null);

    useEffect(() => {
        const unsubscribe = onSnapshot(
            myQuery ? q : collection(appFireStore, transaction),
            (snapshot) => {
                //snapshot 에 doc이 배열 형태로 저장되어 있음 .

                let result = [];
                snapshot.docs.forEach((doc) => {
                    result.push({ ...doc.data(), id: doc.id });
                });

                setDocuments(result);
                setError(null);
            },
            (error) => {
                setError(error.message);
            }
        );
        return unsubscribe; //clean-up 함수
      
    }, [collection]);

    return { documents, error };
}

export default useCollection;

useEffect 훅의 return 값에 함수를 반환하면 clean-up 함수가 된다.
외부에서 데이터를 구독하는 경우 clean-up 함수는 useEffect훅을 사용하는 컴포넌트가 마운트 해제될때 실행되어 구독을 종료한다.

데이터 불러오기

이렇게 만들어준 useCollection에서 데이터를 받아오면 WishList에 뿌려줘야 한다.
key = {item.id}
title 은 {item.title}
text 는 {item.text} 로 데이터를 뿌려줌!

import { useFirestore } from "../../hooks/useFirestore";

function WishList({ wishes }) {
    const { deleteDocument } = useFirestore("wish");

    return (
        <>
            {wishes.map((item) => {
                return (
                    <li key={item.id} className={styles.wishlist_item}>
                        <strong className={styles.wishlist_title}>{item.title}</strong>
                        <div className={styles.wrapper_text_btn}>
                            <p className={styles.wishlist_text}>{item.text}</p>
                        </div>
                    </li>
                );
            })}
        </>
    );
}
export default WishList;

여기까지 다 해주면 리스트가 불러와 지는데,
로그인 한 사용자 뿐만 아니라 다른 유저가 작성한 내용까지 다 불러와지는 문제가 생김,,
이걸 해결하기 위해서는 파이어스토어 쿼리가 필요!

파이어스토어 쿼리 (Firestore queries)

특정한 데이터를 불러오는 DB의 명령어
도큐먼트 중에서도 로그인 한 사용자의 아이디와 일치하는 데이터만 불러올 수 있도록 해준다!

문서의 uid 와 사용자의 uid를 비교해보면 된다.
useCollection 에 보낼 인자에 쿼리를 추가한다. (문서의 uid와 사용자의 uid를 비교하는 쿼리문)

//Wish.jsx
const { documents, error } = useCollection("wish", ["uid", "==", user.uid]);

그리고 위에서 만들어준 useCollection.jsx 에서 코드에 쿼리 관련 내용을 추가해주면 된다!
컨텐츠의 순서가 뒤죽박죽인건 파이어베이스에서 제공하는 orderBy 정렬 함수를 사용한다.
orderBy("createdTime", "desc") desc 는 내림차순을 반환하도록 해준다.

import { collection, onSnapshot, orderBy, query, where } from "firebase/firestore";

function useCollection(transaction, myQuery) { //쿼리 추가 
    const [documents, setDocuments] = useState(null);
    const [error, setError] = useState(null);

    useEffect(() => {
        let q;
        if (myQuery) { //쿼리가 존재한다면
            q = query( //쿼리라는 파이어베이스 함수 실행 
                collection(appFireStore, transaction), //컬렉션 실행
                where(...myQuery), //배열로 받는 마이쿼리 
                orderBy("createdTime", "desc") 
              //앞에서 해준 createdTime과 "desc" -> 내림차순으로 정렬
            );
        }

        const unsubscribe = onSnapshot(
            myQuery ? q : collection(appFireStore, transaction),
            (snapshot) => {
              //마이쿼리가 참이면 q 반환

                let result = [];
                snapshot.docs.forEach((doc) => {
                    result.push({ ...doc.data(), id: doc.id });
                });

                setDocuments(result);
                setError(null);
            },
            (error) => {
                setError(error.message);
            }
        );
        return unsubscribe;
    }, [collection]);

    return { documents, error };
}

export default useCollection;

적용을 하고 리액트 화면으로 돌아오면 아래와 같은 경고 문구가 보여진다..

쿼리문을 두 개 이상 사용할 경우 나타나는 것으로 사용한 쿼리문이 작동할 수 있도록 index를 생성해야 한다. 이거는 그냥 이 링크로 이동해서 색인을 생성하면 해결!

데이터 삭제하기

useFirestore.jsx 에서 데이터 삭제 함수 작성

//컬렉션에서 문서를 제거
	//id 는 삭제할 도큐먼트의 아이디
    const deleteDocument = async (id) => {
        dispatch({ type: "isPending" });
        try {
            const docRef = await deleteDoc(doc(colRef, id));
            dispatch({ type: "deleteDoc", payload: docRef });
        } catch (e) {
            dispatch({ type: "error", payload: e.message });
        }
    };

그리고 디스페치에 deleteDoc을 실행하게 해줬으니 case 에 타입 추가해주기!

 case "deleteDoc":
            return {
                isPending: false,
                document: action.payload,
                success: true,
                error: null,
            };

그리고 이 함수를 실행하게 해주기 위해서

버튼을 만들고 이벤트를 주자 !

<button
	className={styles.delete_btn}
	type="button"
	onClick={() => {
	deleteDocument(item.id);
	}}
>
 🫥
</button>

이렇게까지 하면 삭제도 완 성 - !

프로젝트도 완 성 - !
긴 여정이었다 ...

*이 프로젝트는 인프런 제코베 파이어베이스 수업을 듣고 만든 프로젝트입니다.

profile
Front-End Developer ✨

2개의 댓글

comment-user-thumbnail
2022년 9월 25일

와!! 올라프 너무 귀여운데요?!
게다가 css에 인증과 DB까지 알찬 구성이네요! 좋은 프로젝트 후기 잘 보고 갑니다 멋지네요 +_+

1개의 답글

관련 채용 정보