ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [React] Firebase로 사진, 영상 업로드
    SPA/React.js 2022. 11. 10. 07:51

    1. Storage

    Firebase를 이용해서 사진이나 영상 등의 파일을 업로드하기 위해서는 Firestore(database)를 이용하는 게 아닌, Storage를 이용해야 한다.

    Firestore로 업로드할 수 있긴 하나 용량의 문제도 있고 Firestore는 주로 텍스트 형식의 데이터를 저장하고자 이용하기에

    파일은 Storage를 이용하여 저장하고 해당 url을 Firestore에 저장하는 게 더 적합하다.

     

    우선 Storage를 사용하기 위해 fbase.js에서 getStorage를 export하자.

    // fbase.js
    
    import { initializeApp } from "firebase/app";
    import { getAuth } from "firebase/auth";
    import { getFirestore } from "firebase/firestore";
    import { getStorage } from "firebase/storage";
    
    const firebaseConfig = {
      apiKey: "",
      authDomain: "",
      projectId: "",
      storageBucket: "",
      messagingSenderId: "",
      appId: ""
    };
    
    const app = initializeApp(firebaseConfig);
    export const auth = getAuth();
    export const database = getFirestore();
    export const storage = getStorage();

     


     

    2. 이미지 업로드

    (1) uuid

    이어서 PostFactory Component에서 이미지 업로드 기능을 구현해볼텐데

    우선 그 전에 필요한 패키지를 설치하자.

    $ npm i uuid
    [여기서 uuid란?]
     uuid는 Universal Unique Identifier(범용 단일 식별자)의 약자로 uuid 함수를 호출 시 랜덤으로 문자열이 생성되어 주로 중복되지 않는 고유한 key 값, 혹은 id를 부여할 때 사용한다.

     

    (2) 구조 수정

    이미지 업로드를 위해 구조를 수정해주는데

    이미지 input 추가와 attachment state가 true일 경우(파일을 선택했을 경우), 해당 이미지가 보여지고 사용자가 삭제할 수 있도록 삭제 버튼이 있다는 점이다.

      return (
        <form onSubmit={onSubmit}>
          <div>
            <input name='title' value={title} onChange={onChange} type="text" placeholder="제목을 입력해주세요." required/>
            <input name='contents' value={contents} onChange={onChange} type="text" placeholder="내용을 입력해주세요." required/>
            <input type="submit" value="&rarr;"/>
          </div>
          <label htmlFor = "attach-file">
          <span>Add photos</span>
        </label>
        <input id = "attach-file" type = "file" accept = "image/*" onChange = {onFileChange} style = {{opacity: 0,}} />
        {attachment && (
          <div>
            <img src = {attachment} style = {{backgroundImage: attachment}} alt="PostImg" />
            <div onClick = {onClearAttachment}>
              <span>Remove</span>
            </div>
          </div>
        )}
        </form>
      )

     

    (3) state

    이제 PostFactory에서 이미지 파일을 담을 attachment state를 생성해주고 기능을 구현해줄 함수를 정의해보자.

    // components/PostFactory.js
    
      const [attachment, setAttachment] = useState("");

     

    (4) 함수 정의

    (4-1) onFileChange 

    file input이 변화할 때(파일을 선택했을 때) 실행되는 onFileChange 함수를 정의해주는데

    선택한 파일을 theFile 변수에 저장해주고 FileReader를 이용해 비동기적으로 파일 데이터를 처리해주자.

     

    파일 로드가 끝난 뒤에 처리가 끝난 파일을 attachment에 대입해주며

    파일이 존재할 경우(true) 현재 파일을 데이터 url로 읽어들여 저장해준다.

      const onFileChange = (e) => {
        const {target: { files }} = e;
        const theFile = files[0];
    
        const reader = new FileReader();
        reader.onloadend = (finishedEvent) => {
          const {currentTarget: { result }} = finishedEvent;
          setAttachment(result);
        };
        if (Boolean(theFile)) {
          reader.readAsDataURL(theFile);
        }
      };

     

    (4-2) onSubmit 

    이어서 form이 submit되었을 때 실행되는 onSubmit 함수에 파일을 storage에 저장하는 부분을 추가하는데

    attachment state가 빈 칸이 아닐 때(값이 들어있을 때) storage에 uid와 uuid를 이용한 고유 경로를 생성하여 저장하고

    이를 uploadString(파일 ref, 보낼 파일 데이터, 포맷)으로 파일을 업로드해준다.

     

    해당 이미지를 화면에 보여주기 위하여 getDownloadURL을 이용해 이미지의 주소를 받아온다.

    이 때 파일 업로드할 때 사용했던 uploadString의 객체를 인자로 넣고 ref를 하면 이미지 주소가 나온다.

     

    이를 Posting 객체에 넣어 database에도 이미지 정보가 들어갈 수 있도록 하자.

    import { v4 as uuidv4 } from 'uuid';
    import { ref, uploadString, getDownloadURL } from "@firebase/storage";
    
       const onSubmit = async (e) => {
    
    // ...
    
        let attachmentUrl = "";
        if (attachment !== "") {
          const attachmentRef = ref(storage, `${userObj.uid}/${uuidv4()}`);
          const response = await uploadString(attachmentRef, attachment, "data_url");
          attachmentUrl = await getDownloadURL(response.ref);
        }
    
        const Posting = {
          title: title,
          contents: contents,
          createdAt: Date.now(),
          creatorId: userObj.uid,
          attachmentUrl,
        }

     

    (4-3) onClearAttachment 

    이미지 삭제 버튼을 눌렀을 때 실행되는 onClearAttachment function이다.

    attachment state를 초기화함으로써 이미지 데이터와 url이 초기화되도록 한다.

      const onClearAttachment = () => setAttachment("");

     

    이렇게 게시물 생성 시 이미지도 같이 업로드할 수 있는 기능을 구현했다. (Create)

     


     

    3. 이미지 읽기

    (1) 구조 수정

    이제 업로드된 이미지를 읽기 위해 Posts Component도 수정해주는데

    우선 return문 안에 해당 게시물에 이미지가 존재할 경우 img tag를 통해 해당 이미지가 보여지로독 한다.

    // routes/Posts.js
    
              <h4>{postList.title}</h4>
              <h4>{postList.contents}</h4>
              {postList.attachmentUrl && (
                <img src = {postList.attachmentUrl} width = "50px" height = "50px" alt = "PostImg"/>
              )}
              {isOwner && (

     

    (2) onDelete

    이어서 게시물을 삭제하는 onDelete에 해당 게시물에 이미지가 있다면 deleteObject를 통해 해당 이미지도 storage에서 삭제되도록 하자.

    // routes/Posts.js
    
      const onDelete = () => {
        const yes = window.confirm('삭제하시겠습니까?');
        if (yes) {
          deleteDoc(doc(database, 'posts', postList.id));
          if(postList.attachmentUrl !== "") {
            deleteObject(ref(storage, postList.attachmentUrl));
          }
          navigate('/');
        }
      }

     

    이렇게 하면 이미지를 업로드하고 읽는 기능까지 구현된다.

     

    이렇게 Firebase의 Storage를 이용해서 사진, 영상을 업로드하는 기능을 구현해봤고 다음에는 카테고리를 생성하고 게시물에 카테고리를 적용하여 카테고리에 따라 글이 정렬되도록 해보자.

Designed by Tistory.