Firebase

Firebase를 사용한 트위터 클론 코딩#14(Upload & Delete Tweets With Images)

PON_Z 2022. 8. 15. 20:12

- 이제 이미지 트윗을 업로드 해볼 것이다. 그 전에 Home.js의 아래 부분을 주석처리 해줄 것이다.

  트윗만 올리는 기능을 지우고 트윗에 이미지URL을 올리는 식으로 구현방식을 바꿀 것이다.

- 우선 myFirebase.js에 strorage를 추가한다.

import { initializeApp } from "firebase/app";
import { getAuth } from "firebase/auth";
import { getFirestore } from "firebase/firestore";
import { getStorage } from "firebase/storage";

const firebaseConfig = {
    apiKey: process.env.REACT_APP_API_KEY,
    authDomain: process.env.REACT_APP_AUTH_DOMAIN,
    databaseURL: process.env.REACT_APP_DATABASE_URL,
    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,
    measurementId: process.env.REACT_APP_MEASUREMENT_ID,
  };

const firebaseApp = initializeApp(firebaseConfig);

export const authService = getAuth(firebaseApp);
export const dbService = getFirestore(firebaseApp);
export const storageService = getStorage(firebaseApp);

 

- 오브젝트를 다운로드 및 업로드 하기 위해 firebase에서 reference를 사용할 것이다.

  그리고 특별한 식별자를 랜덤으로 생성하기위해  npm install uuid 를 해준다.

import React, { useEffect, useState } from "react";
import { dbService, storageService } from "myFirebase";
import { addDoc, collection, getDocs, orderBy, query, onSnapshot } from "firebase/firestore";
import {ref, uploadString} from "@firebase/storage";
import { v4 as uuidv4 } from "uuid";
import Tweet from "components/Tweet";

// for Home import
const Home = ({ userObj }) => {
    const [tweet, setTweet] = useState("");
    const [tweets, setTweets] = useState([]);
    const [attachment, setAttachment] = useState();

    const getTweets = async () => {
        const dbTweets = await getDocs(collection(dbService, "tweets"));
        dbTweets.forEach((document) => {
            // tweet의 구조
            const tweetObject = {
                ...document.data(),
                id: document.id,
            };
            setTweets((prev) => [tweetObject, ...prev]);
        });
    }

    const onSubmit = async (event) => {
        // 아무것도 입력하지 않는 행위 방지
        event.preventDefault();
        const fileRef = ref(storageService, `${userObj.uid}/${uuidv4()}`)
        const response = await uploadString(fileRef, attachment, "data_url");
        console.log(response);
        /*
        // tweets collction에 tweet내용과 작성시간을 담은 Doc을 add
        await addDoc(collection(dbService, "tweets"), {
            text: tweet,
            createdAt: Date.now(),
            creatorId: userObj.uid,
        });
        // add한 이후 tweet을 빈 문자열로 초기화
        setTweet("");
        */
    };

- 위와같이 작성하였는데 업로드가 되지 않았다. 원인을 찾아보니 Storage에 Rules가 아래와 같이 설정되어 있었다.

- 아래와 같이 바꿔준다.

- 이제 이미지를 업로드하면 아래와 같이 콘솔에 로그가 찍히고

- 스토리지에도 이미지가 업로드 된 것을 볼 수 있다.

  폴더는 유저 아이디를 기반으로 생성되어 유저마다 파일을 관리할 수 있게 해준다.

 

- 이제 이미지 URL을 다운 받아서 트윗과 함께 올려보도록하자.

 참고로 Firestore DB도 기간이 만료되어서 권한이 빠진 상태였다 true로 바꿔주자.

    const onSubmit = async (event) => {
        // 아무것도 입력하지 않는 행위 방지
        event.preventDefault();
        let attachmentURL ="";

        if(attachment !== "")  {
            // 파일 경로 참조 만들기
            const fileRef = ref(storageService, `${userObj.uid}/${uuidv4()}`);
            // 스토리지 참조경로로 파일 업로드하기
            const response = await uploadString(fileRef, attachment, "data_url");
            // 스토리지 참조 경로에 있는 파일의 URL을 다운로드해서 변수에 넣고 업데이트
            attachmentURL = await getDownloadURL(fileRef);
        }
             
        // tweets collction에 tweet내용과 작성시간을 담은 Doc을 add
        const tweetObject = {
            text: tweet,
            createdAt: Date.now(),
            creatorId: userObj.uid,
            attachmentURL,
        };

        await addDoc(collection(dbService, "tweets"), tweetObject);
        // add한 이후 tweet을 빈 문자열로 초기화
        setTweet("");
        // 파일 미리보기 img 비우기
        setAttachment("");
    };

 

- 잘 트윗되었다.

 

- Tweet.js도 수정하여 트윗에도 이미지 URL을 활용하여 이미지가 보일 수 있게 하자.

- 아래와 같이 글이 사진과 함께 게시되었다.

-  아직 이미지 오브젝트까지 삭제하는 기능은 구현되지 않았으므로 삭제 기능을 구현하자.

  Tweet.js에서 onDeleteClick을 수정하자.

    const onDeleteClick = async() => {
        const ok = window.confirm("Are you sure to delete this tweet?");
        console.log(ok);
        if(ok) {
            // delete tweet
            const tweetTextRef =doc(dbService, "tweets", `${tweetObj.id}`);
            await deleteDoc(tweetTextRef);

            // delete attachment
            const urlRef = ref(storageService, tweetObj.attachmentURL);
            await deleteObject(urlRef);
        }
    };

- 깔끔하게 삭제된다.

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

728x90