본문 바로가기

Server/Firebase

<파이어베이스> 파일 업로드

1. 초기 셋팅

* 콘솔

 

 - 파이어베이스 콘솔에서 storage를 시작하자.

 

 - 아래와 같이 파일을 저장하는 버킷이 생성되면 끝이다.

 

* 코드

 - 셋팅을 위해 만들어 둔 fbase.js 파일에 storage를 추가한다.

 

// fbase.js

// ...
import "firebase/storage"

const firebaseConfig = {
  // ...
};

firebase.initializeApp(firebaseConfig);
// ...
export const storageService = firebase.storage();

 

 - firebase.storage() 를 storageService라는 변수로 export 해주었다.

 

2. 첨부

* 파일 첨부

 - 위처럼 파일선택을 하고, 파일명을 띄우고, 미리보기 사진을 띄워보자.

 

// Home.js
import React, { useState, useEffect } from 'react';
import { dbService, storageService } from 'fbase';
// ...

const Home = ({ userObj }) => {
  // ...
  const [attachment, setAttachment] = useState() 
  const [file, setFile] = useState('')
  
  const onFileChange = (event) => {
    const {target:{files, value}} = event;
    const theFile = files[0];
    const reader = new FileReader();
    setFile(value)
    reader.onloadend = (finishedEvent) => {
      const { currentTarget: {result}} = finishedEvent
      setAttachment(result)
    }
    reader.readAsDataURL(theFile);
  }
  const onClearAttachment = () => {
    setAttachment(null)
    setFile('')
  };
  return (
    <div>
      <form onSubmit={onSubmit}>
        <input value={nweet} onChange={onChange} type="text" placeholder="게시글을 써주세요." maxLength={120} />
        <input type="file" accept="image/*" onChange={onFileChange} value={file}/>
        <input type="submit" value="제출하기" />
        {attachment && (
          <div>
            <img src={attachment} width="50px" height="50px" alt="attachment"/>
            <button onClick={onClearAttachment}>Clear</button>
          </div>
        )}
      </form>
      <div>
        ...
      </div>
    </div>
  );
};

export default Home;

 

 - input type="file" 을 이용하여 파일을 첨부받을 수 있다.

 

 - file 이라는 state는 파일명을 담을 상태이고, attachment는 파일 자체를 의미하는 state이다.

 

 - onChange 속성으로 함수를 주었다. 이 때, event.target 내에 files 는 파일 자체를 갖고 있다. value는 파일명을 갖게 된다.

 

 - 그러므로 value는 file state에 넘겨주었다.

 

 - 파일 자체를 어떻게 관리하느냐가 문제이다. 이 때 사용할 것이 자바스크립트의 fileReader API이다. FileReader 인스턴스를 사용하여 파일을 읽는 객체를 만들었다.

 

 - onloadend 를 통해 파일 읽는것이 끝나는 리스너를 만들어 주었다. 이 때 생기는 이벤트 객체의 currentTarget 내의 result에 파일이 복잡한 텍스트로 변경된 값이 저장되어 있다.

 

 - 파일을 읽으려면 readAsDataURL 메서드를 사용한다. 완전히 읽어져서 담기면 onloadend 메서드가 실행된다.

 

 - 이렇게 만들어진 결과를 attachment state에 담는다. 이를 브라우저 주소창에 입력해보면 브라우저는 텍스트를 해석해 사진을 보여준다.

 

 - 다시 return을 보면 attachment가 있을 때 src에 넣어 보여주도록 하였다. 삭제 버튼도 만들어두었다.

 

* 첨부 제거

 - 위의 첨부파일을 제거하려면 제거버튼을 누르면 되도록 설계해두었다.

 

 - 버튼 onClick에 넣어둔 onClearAttachment를 살펴보자.

 

// ...
  const onClearAttachment = () => {
    setAttachment(null)
    setFile('')
  };
// ...

 

 - Clear버튼을 누르면 attachment와 file 을 비우도록 하였다.

 

3. 업로드

 - 이제 파이어베이스의 storage에 파일을 업로드 해보자.

 

// Home.js
import React, { useState, useEffect } from 'react';
import { v4 as uuidv4 } from "uuid"
import { dbService, storageService } from 'fbase';
import Post from 'components/Post'


// ...

  const onSubmit = async (event) => {
    event.preventDefault();
    let attachmentUrl = "";
    if (attachment !== "") {
      const attachmentRef = storageService.ref().child(`${userObj.uid}/${uuidv4()}`);
      const response = await attachmentRef.putString(attachment, "data_url")
      attachmentUrl = await response.ref.getDownloadURL()
    }
    const postObj = {
        text: post,
        createdAt: Date.now(),
        creatorId: userObj.uid,
        attachmentUrl,
    }
    await dbService.collection("posts").add(postObj);
    setNweet('');
    setAttachment('');
    setFile('')
  };

 

 - 지난 장에서 만든 onSubmit함수에 파일을 업로드 하는 로직이 추가되었다.

 

 - 파일명을 랜덤으로 만들기 위해서 uuidv4 를 사용하였다.

 

 - 사진의 url 정보를 담을 attachmentUrl을 먼저 선언한다. attchment 가 있는지 확인하고 없으면 빈 url을 객체에 넣어서 db에 전달할 것이다.

 

 - 만약 attachment 가 있다면, storage의 버킷에 넣어준다.

 

 - 먼저 storageService.ref()의 child 메서드를 이용해서 이미지의 경로를 만들어 준다. 유저의 id를 폴더로 하는 path를 만들어 주었다.

 

 - put 메서드를 사용할 수 있다. putString으로 문자열을 전달할 수 있는데, 두 번째 인자로는 format을 입력해야한다. 이렇게하면 버킷에 저장된 것을 확인할 수 있다.

 

 - 이제 필요한 것은 저장된 이미지의 url이다. 이 url을 img태그에 넣어야 이미지가 보일 것이기 때문이다.

 

 - putString이 일어나고 나면 응답을 주는데, 이 응답에서 ref속성에 getDownloadURL 메서드를 사용하면 그 링크를 받아올 수 있다.

 

 - 이제 그 링크를 객체에 넣고, 객체는 파이어베이스 컬렉션에 넣는다. 그리고 Post 컴포넌트에 랜더링하면 끝이다.

 

 

4. 삭제

 - 삭제는 Post.js 컴포넌트에서 확인해보자. 지난 장에서 만들었던 삭제 함수에 조금 더 추가만 하면 된다.

 

// Post.js
import { dbService, storageService } from 'fbase';
import React, { useState } from 'react';

const Post = ({ postObj, isOwner }) => {
  // ...
  const onDeleteClick = async () => {
    const ok = window.confirm("삭제하시겠습니까?");
    console.log(ok)
    if (ok) {
      await dbService.doc(`posts/${postObj.id}`).delete();
      await storageService.refFromURL(postObj.attachmentUrl).delete();
    }
  }
 
 // ...

 

 - 먼저 storageService를 import하였다.

 

 - 삭제를 하려면 당연히 버킷내의 파일의 경로를 알아야한다. 하지만 이 경로를 따로 객체에 저장해주지 않았기때문에 번거로울 수 있다.

 

 - 그러나 다행히 경로를 찾아주는 메서드를 파이어베이스에서 지원한다. refFromURL메서드를 사용하여 파일의 url을 넣어주면 storage내의 경로를 알려준다. 이를 delete메서드로 지워주기만하면 된다.

 

 

 


 

참고

 

 

 

firestore | JavaScript SDK  |  Firebase

Reference for firestore

firebase.google.com

 

 

Watch Now - 노마드 코더 Nomad Coders

 

nomadcoders.co