TIL_ver9 Firebase 시작하기 3 (firestore storage이용해서 사진등록하기)

이고운·2023년 4월 6일
0

firebase_게시판

목록 보기
3/5

1. Storage 이용하여 파일 업로드

1) storage 세팅하기

  • 콘솔 - storage 시작 - bucket만들기 (파일 넣는곳)

2) 사진 첨부기능 만들기

  • fweet에 사진을 첨부해야하기 때문에 방법을 변경해야함

(1) Home.js 파일 업로드 input 추가

(2) 사진 첨부시 미리보기 기능 만들기

Home.js

 const [fileAddress, setFileAddress] = useState("");

 const onFileChange = (event) => {
    const {
      target: { files },
    } = event;
    const theFile = files[0]; 
    // console.log(theFile);
    const reader = new FileReader();
    //파일로딩이 끝날때 finishedevent를 갖게 됨
    reader.onloadend = (finishedEvent) => {
      // console.log(finishedEvent); 여기서 result값이 string으로 아주 길게 나옴 이걸 state로 저장할것임
      //result를 카피해서 새창에 붙여넣으면 사진이 뜸 -> 이미지경로가되는것
      const {
        currentTarget: { result },
      } = finishedEvent;
      //파일
      setFileAddress(result);
    };
    //데이터를 얻음
    reader.readAsDataURL(theFile);
  };

...
return(
{fileAddress && (
                <div className="imgWrap">
                  <img
                    src={fileAddress}
                    width="100px"
                    height="100px"
                    alt="img"
                  />
                  <div className="clearButton">
                    <button onClick={onClearPhotoClick}>Clear</button>
                  </div>
                </div>
              )}
            </div>
)

(3) 사진 첨부 취소 기능


Home.js

const onClearPhotoClick = () => {
   setFileAddress(null);
 };

...
return(
<button onClick={onClearPhotoClick}>Clear</button>
)

3) 사진 storage 저장

(1) bucket에 업로드할 수 있도록 import

  • Home.js에 handleSubmit 함수를 수정
  • 사진을 먼저 업로드하고 그 url을 받아서 fweet에 추가하여 업로드할 것임.
  • 먼저 storage myBase.js에 import하기

    import { getStorage } from "firebase/storage";
    export const storageService = getStorage();

(2) 이미지 string URL 가져오기 - uploadString함수 이용

참고문서 문자열에서 업로드 부분

  • 파일에 대한 storage ref 만들기
  • storage 업로드 기능 만들기 - 우리는 url string이 있음. 이걸로 만들기
Home.js
import { ref, uploadString, getDownloadURL } from "firebase/storage";


  const handleSubmit = async (e) => {
    e.preventDefault();
    const fileRef = ref(storageService, //하위위치 폴더 만들기 모든 유저의 사진은 아이디와 분리되어있음. 그리고 사진에다가 이름을 랜덤으로 만들어 주기`${userObj.uid}/${uuidv4()}`);
    const response = await uploadString(fileRef, fileAddress, "data_url");
      console.log(respond)
  };
  • bucket을 확인해보면 userObj.uid로 만든 폴더명이 생성되어있음
  • 클릭하면 랜덤이름을 가진 파일이 나옴

(3) URL을 통해 데이터 다운로드 - getDownloadURL 함수 이용

참고문서: https://firebase.google.com/docs/storage/web/download-files?hl=ko

(4) handleSubmit 함수 - fweet기능 수정

Home.js
import { ref, uploadString, getDownloadURL } from "firebase/storage";


  const handleSubmit = async (e) => {
    e.preventDefault();
    const fileRef = ref(storageService, 
    const response = await uploadString(fileRef, fileAddress, "data_url");
     //콘솔 찍으면 사진의 url을 다운받게 됨.
      // console.log(await getDownloadURL(response.ref));
    fileUrl = await getDownloadURL(response.ref);
    
    const fweetobject = {
      text: content,
      userName: userObj.displayName,
      createAt: Date.now(),
      creatorId: userObj.uid,
      fileUrl //object에 fileUrl 추가
    };
    await addDoc(collection(dbService, "fweets"), fweetobject);
    setContent("");
    setFileAddress("");
  }; 
  • 이러면 field에 fileUrl이 추가된 내용을 확인할 수 있음.
  • 이미지 첨부 내역도 fileAddress이 있는 경우에 img 태그가 보이도록 수정
  • 여기서 포인트!! 때로는 fileAddress이 없을 수도 있음.
    있을 때만 이미지 업로드, 다운로드 함수가 적용되도록 바꾸기
Home.js
 
 const handleSubmit = async (e) => {
    e.preventDefault();
    let fileUrl = ""; //사진이 없다면 비어있는 string
    if (fileAddress !== "") {
      const fileRef = ref(storageService, `${userObj.uid}/${uuidv4()}`);
      const response = await uploadString(fileRef, fileAddress, "data_url");
      fileUrl = await getDownloadURL(response.ref);
    }
   ...

4) storage 삭제

fweet한 내용을 storage에서 삭제해야함.
참고 문서 : https://firebase.google.com/docs/storage/web/delete-files?hl=ko

  • 삭제하려면 url을 알고 있어야함. 그러나 우리는 랜덤 이름으로 넣었음.(uuidv4) 하지만 우리에게는 reference가 있지!
  • ref는 document를 수정하거나 삭제할 때도 필요하고, collection안에 무언갈 만들고 싶다면 그 때도 필요함.
  • 원래 ver9 이전에는 refFromUrl이라는 게 있었는데 ver9은 그냥 ref로 가능한듯 하다.

(1) 필요한 함수 import

import { ref, deleteObject } from "firebase/storage";

(2) 삭제함수 수정

Fweet.js

  const handleDelete = async () => {
    const ok = window.confirm("Are you sure?");
    if (ok) {
      await deleteDoc(FweetTextRef);
      await deleteObject(ref(storageService, fweetObj.fileUrl));
    }
  };

⭐️ 완성화면

❗️어려웠던 점
역시나 ver9으로 하는 것이 쉽지 않았다..
또 이미 firestore로 작성했던 부분을 사진을 추가 저장함으로써
storage함수로 바꾸는 점이 어려웠음..
다른 사람들이 한 것도 참고하고 공식문서 계속보면어 각 메소드가 어떤 역할을 하는지 파악하기 위해 애썼다.
마지막에 사진 첨부 취소하고 같은 사진 재첨부하려니까 안되어서 확인해보니
input에 value가 삭제 안되는 거 같아 첨부취소시 value값 공란으로 두는 것으로 바꿨다. 사진 재첨부 되긴하는데 수정이 좀 필요할 듯 싶다..

➕➕ ❗️오류 수정
이 때 작업할 때는 몰랐는데 정리하고 보니 삭제할 때 에러가 발생했다.
사진이 있는 경우에 삭제할 때는 오류가 안나서 몰랐음. ;;;
그러나 사진이 없는 경우에는 아래와 같은 오류가 발생했다.

Uncaught (in promise) FirebaseError: Firebase Storage: The operation 'deleteObject' cannot be performed on a root reference, create a non-root reference using child, such as .child('file.png'). (storage/invalid-root-operation)

해석이랑 검색해보니까 참조 문제 인거 같아서 myBase.js 거치지 않고
다이렉트로 import하고 다양하게 바꿔봤는데 안됐음.
알고보니까 사진이 없는 경우에 즉 storage에 저장된게 없는 경우에
(단순 글로된 fweet) 삭제할 때 오류가 발생하는 거였음.
생각해보면 당연함...deleteObject는 storage메소드니까 해당이 안되어서
에러가 생기는 거였음...
결국에는 조건문을 달아서 fweetObj.fileUrl !== ""일 때 함수 실행하도록 수정함.
이런 조건문 잊지말고 달자구!!😉

profile
자 이제 시작이야~ 내 꿈을~ 내 꿈을 위한 여행~~🌈

0개의 댓글