๐ŸŒŸ Firebase Storage: File URL

summereuna๐Ÿฅยท2022๋…„ 4์›” 12์ผ

๐ŸŒŸ Twinkle (React, Firebase)

๋ชฉ๋ก ๋ณด๊ธฐ
20/42

์•—..๋ฒ„ํ‚ท์ฃผ์†Œ/ํŒŒ์ผpath ๋ณต์‚ฌํ•ด์„œ ๋ธŒ๋ผ์šฐ์ € ์ฃผ์†Œ์ฐฝ์— ๋ถ™์—ฌ ๋„ฃ๊ธฐ ํ–ˆ๋Š”๋ฐ ์ด๋ฏธ์ง€๊ฐ€ ์•ˆ๋œจ์Ÿˆ๋‚˜...?
์Šคํ† ๋ฆฌ์ง€๊ฐ€ ๋ณด์•ˆ ๊ฐ•ํ™”๋๊ฑฐ๋‚˜ ์•„๋‹ˆ๋ฉด Rules ๋•Œ๋ฌธ์ผ์ง€๋„..

url์„ ๋‹ค์šด๋กœ๋“œ ํ•˜๋ ค๋ฉด public url์„ ๋‹ค์šด๋กœ๋“œ๋ฐ›์•„์•ผ ํ•œ๋‹ค.

Storage์—์„œ ํŒŒ์ผ ๋‹ค์šด๋กœ๋“œ ๋ฐ›๊ธฐ


Cloud Storage์˜ Reference์— ๋Œ€ํ•ด getDownloadURL()๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ํŒŒ์ผ์˜ ๋‹ค์šด๋กœ๋“œ URL์„ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๋‹ค.

  • ์˜ˆ์‹œ
import { getStorage, ref, getDownloadURL } from "firebase/storage";
//
const storage = getStorage();
getDownloadURL(ref(storage, 'images/stars.jpg'))
  .then((url) => {
    // ์œ„์˜ getDownloadURL()๋ฅผ ํ†ตํ•ด ๋ฐ˜ํ™˜๋˜๋Š” 'url'์€ 'images/stars.jpg'์˜ ๋‹ค์šด๋กœ๋“œ URL์ด๋‹ค.
//
    // ์ด ํŒŒ์ผ์€ ์ง์ ‘ ๋‹ค์šด๋กœ๋“œํ•  ์ˆ˜ ์žˆ๋‹ค.
    const xhr = new XMLHttpRequest();
    xhr.responseType = 'blob';
    xhr.onload = (event) => {
      const blob = xhr.response;
    };
    xhr.open('GET', url);
    xhr.send();
//
    // ๋˜๋Š” <img> ์š”์†Œ์— ์‚ฝ์ž…ํ•  ์ˆ˜ ์žˆ๋‹ค.
    const img = document.getElementById('myimg');
    img.setAttribute('src', url);
  })
  .catch((error) => {
    // ์˜ค๋ฅ˜ ์ฒ˜๋ฆฌ๋Š” catch ๊ตฌ๋ฌธ์œผ๋กœ ํ•˜๋ฉด ๋œ๋‹ค.
  });

๐Ÿ“ routes/Home.js

//

import { ref, uploadString, getDownloadURL } from "@firebase/storage";

//

const onSubmit = async (event) => {
  event.preventDefault();

  //storage์— ํŒŒ์ผ ๋ฐ์ดํ„ฐ๊ฐ€ ์—…๋กœ๋“œ๋  ์œ„์น˜ ๊ฐ€๋ฆฌํ‚ค๋Š” ๋ ˆํผ๋Ÿฐ์Šค ์ƒ์„ฑํ•˜๊ธฐ
  const fileRef = ref(storageService, `${userObj.uid}/${uuidv4()}`);

  //๋ ˆํผ๋Ÿฐ์Šค(fileRef)๊ฐ€ ๊ฐ€๋ฆฌํ‚ค๋Š” ์œ„์น˜์— ์ฐ์œผ๋กœ ๋ฐ์ดํ„ฐ ์—…๋กœ๋“œํ•˜๊ธฐ
  //fileRef๊ฐ€ ๊ฐ€๋ฆฌํ‚ค๋Š” ์œ„์น˜์— attachment์— ๋“ค์–ด์žˆ๋Š” ์ฒจ๋ถ€ํŒŒ์ผ url์„ ๋„ฃ์–ด๋ผ, ํฌ๋งทdata_url
  const response = await uploadString(fileRef, attachment, "data_url");
  console.log(response);
  
  //๐Ÿ”ฅ response์˜ ref, ์ฆ‰ ์Šคํ† ๋ฆฌ์ง€์— ์—…๋กœ๋“œํ•œ ํŒŒ์ผ ์œ„์น˜์— ์žˆ๋Š” ๊ทธ ํŒŒ์ผ์˜ URL์„ ๋‹ค์šด๋กœ๋“œํ•ด์„œ
  // attachmentUrl ๋ณ€์ˆ˜์— ๋„ฃ์–ด์ฃผ์ž.
  let attachmentUrl;
  attachmentUrl = await getDownloadURL(response.ref);
  //๐Ÿ”ฅ ๊ทธ๋Ÿฌ๊ณ  ๋‚˜์„œ attachmentUrl๋ฅผ ์ฝ˜์†”์— ์ฐ์–ด๋ณด์ž!
  console.log(attachmentUrl);

  //ํŠธ์œ—ํ•˜๊ธฐ ๋ˆ„๋ฅด๋ฉด ์ƒˆ๋กœ์šด document ์ƒ์„ฑํ•˜๊ธฐ๋Š” ํ˜„์žฌ ์ฃผ์„์ฒ˜๋ฆฌ
};

//
  • ์˜คํ˜ธ ์Šคํ† ๋ฆฌ์ง€์— ์—…๋กœ๋“œํ•œ ํŒŒ์ผ์˜ URL์„ ๋‹ค์šด๋กœ๋“œURL๋กœ ์ž˜ ๋‹ค์šด๋ฐ›์•˜๋‹ค!!

๋‹ค์šด๋กœ๋“œURL ํŠธ์œ— ์˜ค๋ธŒ์ ํŠธ์— ๋„ฃ๊ธฐ


์ด์ œ ๋‹ค์šด๋กœ๋“œ ๋ฐ›์€ URL์„ ํŠธ์œ—ํ•  ๋•Œ ๊ฐ™์ด ๋„ฃ์–ด ์ฃผ์ž!
์ฃผ์„ ํ’€๋Ÿฌ ๊ณ ๊ณ ์‹ฑ~!!!

//

import { ref, uploadString, getDownloadURL } from "@firebase/storage";

//

const onSubmit = async (event) => {
  event.preventDefault();

  //storage์— ํŒŒ์ผ ๋ฐ์ดํ„ฐ๊ฐ€ ์—…๋กœ๋“œ๋  ์œ„์น˜ ๊ฐ€๋ฆฌํ‚ค๋Š” ๋ ˆํผ๋Ÿฐ์Šค ์ƒ์„ฑํ•˜๊ธฐ
  const fileRef = ref(storageService, `${userObj.uid}/${uuidv4()}`);

  //๋ ˆํผ๋Ÿฐ์Šค(fileRef)๊ฐ€ ๊ฐ€๋ฆฌํ‚ค๋Š” ์œ„์น˜์— ์ฐ์œผ๋กœ ๋ฐ์ดํ„ฐ ์—…๋กœ๋“œํ•˜๊ธฐ
  //fileRef๊ฐ€ ๊ฐ€๋ฆฌํ‚ค๋Š” ์œ„์น˜์— attachment์— ๋“ค์–ด์žˆ๋Š” ์ฒจ๋ถ€ํŒŒ์ผ url์„ ๋„ฃ์–ด๋ผ, ํฌ๋งทdata_url
  const response = await uploadString(fileRef, attachment, "data_url");
  console.log(response);

  //response์˜ ref, ์ฆ‰ ์Šคํ† ๋ฆฌ์ง€์— ์—…๋กœ๋“œํ•œ ํŒŒ์ผ ์œ„์น˜์— ์žˆ๋Š” ๊ทธ ํŒŒ์ผ์˜ URL์„ ๋‹ค์šด๋กœ๋“œํ•ด์„œ
  //attachmentUrl ๋ณ€์ˆ˜์— ๋„ฃ์–ด์ฃผ์ž.
  let attachmentUrl;
  attachmentUrl = await getDownloadURL(response.ref);
  //๊ทธ๋Ÿฌ๊ณ  ๋‚˜์„œ attachmentUrl๋ฅผ ์ฝ˜์†”์— ์ฐ์–ด๋ณด์ž!
  console.log(attachmentUrl);

  //๐Ÿ”ฅ ํŠธ์œ— ์˜ค๋ธŒ์ ํŠธ์— ๋‹ค์šด๋กœ๋“œํ•œ attachmentUrl ์ถ”๊ฐ€
  const tweetObj = {
    text: tweet, //tweet(value๋กœ tweet state ๊ฐ’)
    createdAt: serverTimestamp(), //Date.now(),๋กœ ํ•ด๋„ ๋˜์ง€๋งŒ ์ด์™• ์žˆ๋Š”๊ฑฐ ํ•จ ์จ๋ณด์ž(ํƒ€์ž„์กด ๋™๋ถ์•„3 = ์„œ์šธ๋กœ ์„ค์ •๋˜์–ด ์žˆ์Œ)
    creatorId: userObj.uid,
    attachmentUrl,
  };
  
  //๐Ÿ”ฅ ํŠธ์œ—ํ•˜๊ธฐ ๋ฒ„ํŠผ ํด๋ฆญํ•˜๋ฉด tweetObj ํ˜•ํƒœ๋กœ ์ƒˆ๋กœ์šด document ์ƒ์„ฑํ•˜์—ฌ tweets ์ฝœ๋ ‰์…˜์— ๋„ฃ๊ธฐ
  await addDoc(collection(dbService, "tweets"), tweetObj);

  //๐Ÿ”ฅ state ๋น„์›Œ์„œ form ๋น„์šฐ๊ธฐ
  setTweet("");
  
  //๐Ÿ”ฅ ํŒŒ์ผ ๋ฏธ๋ฆฌ๋ณด๊ธฐ img src ๋น„์›Œ์ฃผ๊ธฐ
  setAttachment("");
};

๋‹คํ๋จผํŠธ์— ๋‹ค์šด๋กœ๋“œurl ๋„ฃ์–ด์คฌ์œผ๋‹ˆ storage ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ db์ธfirestore์—๋„ ์—…๋กœ๋“œ ๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•ด๋ณด์ž!

  1. ์ด๋ฏธ์ง€ ์ฒจ๋ถ€ํ•ด์„œ ํŠธ์œ—ํ•˜๊ธฐ

  2. ์Šคํ† ๋ฆฌ์ง€์—๋Š” ์ด๋ฏธ์ง€ ์ž˜ ์—…๋กœ๋“œ๋จ!

  3. ํŒŒ์ด์–ด์Šคํ† ์–ด(db)์—๋„ ์Šคํ† ๋ฆฌ์ง€๋กœ ์—…๋กœ๋“œ๋œ ํŒŒ์ผ ์œ„์น˜๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” ref๋ฅผ ์ฐธ์กฐํ•˜์—ฌ ํŒŒ์ผurl์„ ๋‹ค์šด๋กœ๋“œํ•˜์—ฌ attachmentUrl๋กœ ์ž˜ ๋“ค์–ด๊ฐ„ ๊ฒƒ์„ ํ™•์ธ! attachmentUrl์— ์ ํžŒ url์„ ๋ธŒ๋ผ์šฐ์ € ์ฃผ์†Œ์ฐฝ์— ์ž…๋ ฅ ์‹œ ์ฐœ๋‹ˆ์‚ฌ์ง„์ด ์ž˜ ๋œจ๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Œ ^3^!


attachmentUrl์„ ํŠธ์œ—์— ๋ณด์ด๊ฒŒ ํ•˜๊ธฐ


์˜ˆ์ด~~ ์ด์ œ Tweet.js ์ปดํฌ๋„ŒํŠธ์—์„œ ๋‹คํ๋จผํŠธ์˜ attachmentUrl์„ img src์— ๋„ฃ์–ด์„œ ํŠธ์œ—ํ•œ ์ด๋ฏธ์ง€ ํ™”๋ฉด์— ๋ณด์ด๊ฒŒ ํ•ด๋ณด์ž.

๐Ÿ“ components/Tweet.js

//
<>
  <h4>{tweetObj.text}</h4>
  {/*๐Ÿ”ฅ ์ด๋ฏธ์ง€ ์—…๋กœ๋“œ ํ–ˆ์„ ๋•Œ๋งŒ ๋ณด์ด๊ฒŒ*/}
  {tweetObj.attachmentUrl && (
    <img src={tweetObj.attachmentUrl} alt="image" width="500" />
  )}
  {/*ํŠธ์œ— ์ฃผ์ธ์ธ ๊ฒฝ์šฐ๋งŒ ์‚ญ์ œ/์ˆ˜์ • ๋ฒ„ํŠผ ๋ณด์ด๊ฒŒ*/}
  {isOwner && (
    <>
      <button onClick={onDeleteClick}>์‚ญ์ œ</button>
      <button onClick={toggleEditing}>์ˆ˜์ •</button>
      </>
  )}
  </>

ํ•˜์ง€๋งŒ!! ๋•Œ๋กœ๋Š” attchment๊ฐ€ ์—†๋‹ค. ์ฆ‰, ์ด๋ฏธ์ง€ ์—…๋กœ๋“œ ์•ˆํ•˜๊ณ  ํŠธ์œ—๋งŒ ์ž‘์„ฑํ•  ๋•Œ๋„ ์žˆ๋‹ค.

  • ์ง€๊ธˆ ์ƒํƒœ๋กœ๋Š” ์ด๋ ‡๊ฒŒ ๋œฌ๋‹ค๋Š” ์‚ฌ์‹ค... ์ฒจ๋ถ€ ์ด๋ฏธ์ง€ ์—†์ด text๋งŒ ์ž‘์„ฑํ•˜๊ณ  ํŠธ์œ—ํ•˜๋ ค๊ณ  ํ–ˆ๋”๋‹ˆ ์˜ค๋ฅ˜ ๋œฌ๋‹ค ^^!

๋”ฐ๋ผ์„œ const [attachment, setAttachment] = useState(""); ๋กœ ๋นˆ๊ฐ’์œผ๋กœ ๋น„์›Œ๋‘๋Š”๊ฒƒ์„ ๋””ํดํŠธ๋กœ ํ•˜์ž.
์•„๋ž˜ ์ฝ”๋“œ๋ณด๋ฉฐ ๋”ฐ๋ผ๊ฐ€๊ธธ ์ถ”์ฒœ..!

๐Ÿ“ routes/Home.js

//getDownloadURL ์ž„ํฌํŠธ
import { ref, uploadString, getDownloadURL } from "@firebase/storage";

//์‚ฌ์ง„ ์ฒจ๋ถ€ ์—†์ด ํ…์ŠคํŠธ๋งŒ ํŠธ์œ—ํ•˜๊ณ  ์‹ถ์„ ๋•Œ๋„ ์žˆ์œผ๋ฏ€๋กœ ๊ธฐ๋ณธ ๊ฐ’์„ ""๋กœ ํ•ด์•ผํ•œ๋‹ค.
//ํŠธ์œ—ํ•  ๋•Œ ํ…์ŠคํŠธ๋งŒ ์ž…๋ ฅ์‹œ ์ด๋ฏธ์ง€ url ""๋กœ ๋น„์›Œ๋‘๊ธฐ ์œ„ํ•จ
const [attachment, setAttachment] = useState("");

const onSubmit = async (event) => {
  event.preventDefault();
  let attachmentUrl = "";
  
  //์ด๋ฏธ์ง€ ์ฒจ๋ถ€ํ•˜์ง€ ์•Š๊ณ  ํ…์ŠคํŠธ๋งŒ ์˜ฌ๋ฆฌ๊ณ  ์‹ถ์„ ๋•Œ๋„ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— attachment๊ฐ€ ์žˆ์„๋•Œ๋งŒ ์•„๋ž˜ ์ฝ”๋“œ ์‹คํ–‰
  //์ด๋ฏธ์ง€ ์ฒจ๋ถ€ํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ์—” attachmentUrl=""์ด ๋œ๋‹ค.
  if (attachment !== "") {
    //ํŒŒ์ผ ๊ฒฝ๋กœ ์ฐธ์กฐ ๋งŒ๋“ค๊ธฐ
    const attachmentRef = ref(storageService, `${userObj.uid}/${uuidv4()}`);
    //storage ์ฐธ์กฐ ๊ฒฝ๋กœ๋กœ ํŒŒ์ผ ์—…๋กœ๋“œ ํ•˜๊ธฐ
    const response = await uploadString(attachmentRef, attachment, "data_url");
    //storage ์ฐธ์กฐ ๊ฒฝ๋กœ์— ์žˆ๋Š” ํŒŒ์ผ์˜ URL์„ ๋‹ค์šด๋กœ๋“œํ•ด์„œ attachmentUrl ๋ณ€์ˆ˜์— ๋„ฃ์–ด์„œ ์—…๋ฐ์ดํŠธ
    attachmentUrl = await getDownloadURL(response.ref);
  }
  
  //ํŠธ์œ— ์˜ค๋ธŒ์ ํŠธ
  const tweetObj = {
    text: tweet,
    createdAt: Date.now(),
    creatorId: userObj.uid,
    attachmentUrl,
  };
  
  //ํŠธ์œ—ํ•˜๊ธฐ ๋ˆ„๋ฅด๋ฉด tweetObj ํ˜•ํƒœ๋กœ ์ƒˆ๋กœ์šด document ์ƒ์„ฑํ•˜์—ฌ nweets ์ฝœ๋ ‰์…˜์— ๋„ฃ๊ธฐ
  await addDoc(collection(dbService, "tweets"), tweetObj);
  
  //state ๋น„์›Œ์„œ form ๋น„์šฐ๊ธฐ
  setTweet("");
  
  //ํŒŒ์ผ ๋ฏธ๋ฆฌ๋ณด๊ธฐ img src ๋น„์›Œ์ฃผ๊ธฐ
  setAttachment("");
};



//์ฒจ๋ถ€ ํŒŒ์ผ url ๋„ฃ๋Š” state์ธ attachment ๋น„์›Œ์„œ ํ”„๋ฆฌ๋ทฐ img src ์—†์• ๊ธฐ
const onClearAttachment = () => {
  //null์—์„œ ๋นˆ ๊ฐ’("")์œผ๋กœ ์ˆ˜์ •, ํŠธ์œ—ํ•  ๋•Œ ํ…์ŠคํŠธ๋งŒ ์ž…๋ ฅ์‹œ ์ด๋ฏธ์ง€ url ""๋กœ ๋น„์›Œ๋‘๊ธฐ ์œ„ํ•จ
  setAttachment("");
};
profile
Always have hope๐Ÿ€ & constant passion๐Ÿ”ฅ

0๊ฐœ์˜ ๋Œ“๊ธ€