๐ŸŒŸ Firebase Storage: ์ด๋ฏธ์ง€ ํ”„๋ฆฌ๋ทฐ

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

๐ŸŒŸ Twinkle (React, Firebase)

๋ชฉ๋ก ๋ณด๊ธฐ
18/42
post-thumbnail

ํŠธ์œ—์—๋Š” text๋งŒ ์žˆ๋Š”๊ฒŒ ์•„๋‹ˆ๋ผ ์ด๋ฏธ์ง€/๋™์˜์ƒ ๋“ฑ๋„ ์žˆ๋‹ค.
์ด๋ฅผ ๊ตฌํ˜„ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” Firebase์˜ Storage๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค.

bucket์€ ๋‚ด ํŒŒ์ผ์„ ๋„ฃ๋Š” ๊ณณ์ด๋‹ค.


ํŠธ์œ—ํ•  ๋•Œ ์ด๋ฏธ์ง€ ์ฒจ๋ถ€ ๊ธฐ๋Šฅ ๋„ฃ๊ธฐ


ํŠธ์œ—ํ•  ๋•Œ ์‚ฌ์ง„์„ ์ฒจ๋ถ€ํ•  ์ˆ˜ ์žˆ๋„๋ก type์ด file์ด๊ณ  ์ด๋ฏธ์ง€ ํŒŒ์ผ๋งŒ ์ฒจ๋ถ€๊ฐ€๋Šฅํ•œ input์„ ๋งŒ๋“ ๋‹ค.

๐Ÿ“ routes/Home.js

<div>
  <form onSubmit={onSubmit}>
    <input
      type="text"
      placeholder="๋ฌด์Šจ ์ผ์ด ์ผ์–ด๋‚˜๊ณ  ์žˆ๋‚˜์š”?"
      maxLength={120}
      value={tweet}
      onChange={onChange}
      />
    <input type="file" accept="image/*" />
    <input type="submit" value="ํŠธ์œ—ํ•˜๊ธฐ" />
  </form>
</div>

์ด๋ฏธ์ง€ ํŒŒ์ผ์„ ์„ ํƒ ์‹œ ๋ฏธ๋ฆฌ๋ณด๊ธฐ ์ œ๊ณต


ํŠธ์œ—ํ•  ๋•Œ ์ด๋ฏธ์ง€ ํŒŒ์ผ์„ ์ฒจ๋ถ€ํ•˜๋ ค๊ณ  ์„ ํƒํ•˜๋ฉด ๋ฏธ๋ฆฌ๋ณด๊ธฐ๋ฅผ ์ œ๊ณตํ•˜์ž.

  1. file input์— onChange ์ด๋ฒคํŠธ๋ฅผ ์ค€๋‹ค.
<input type="file" accept="image/*" onChange={onFileChange} />
  1. onChange ์ด๋ฒคํŠธ๋ฅผ ์ˆ˜์‹ ํ•˜๋Š” onFileChange ๋ฆฌ์Šค๋„ˆ์—์„œ event๋ฅผ ์ฝ˜์†”์— ์ฐ์–ด๋ณด์ž.
    const onFileChange = (event) => {
      console.log(event);
    };
  • event.target.files์—์„œ ์„ ํƒํ•œ ํŒŒ์ผ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค!

    • files์—๋Š” FileList๊ฐ€ ์žˆ๋Š”๋ฐ ์ฒซ ๋ฒˆ์งธ(0) ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ๋ณด๋‹ˆ name, type์— ์ •๋ณด๊ฐ€ ๋‹ค ๋œฌ๋‹ค.
  • ํŒŒ์ผ๋ฆฌ์ŠคํŠธ์—์„œ ์ฒซ๋ฒˆ์งธ ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ๊ฐ€์ ธ์˜ค์ž.

    //file ๋ฏธ๋ฆฌ๋ณด๊ธฐ ์ œ๊ณต
    const onFileChange = (event) => {
      //console.log(event);
      const {
        target: { files },
      } = event;
      //ํŒŒ์ผ์€ ํ•˜๋‚˜๋งŒ ๋„ฃ์„ ์ˆ˜ ์žˆ๊ฒŒ..^^;;
      const theFile = files[0];
      console.log(theFile);
    };

fileReader API ์‚ฌ์šฉํ•˜์—ฌ ํŒŒ์ผ ์ฝ๊ธฐ


  1. ํŒŒ์ผ์„ ๊ฐ€์ ธ์˜ค๋Š”๋ฐ ์„ฑ๊ณตํ–ˆ์œผ๋‹ˆ ์ด์ œ ํŒŒ์ผ์„ ์ฝ์–ด์™€์„œ ์‚ฌ์šฉ์ž์—๊ฒŒ ๋ณด์—ฌ์ค˜์•ผ ํ•œ๋‹ค.

FileReader API
ํŒŒ์ผ๋ฆฌ๋” API๋Š” ํŒŒ์ผ ์ฝ์–ด์„œ ์ €์žฅํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค€๋‹ค.

๐Ÿ“ routes/Home.js

const onFileChange = (event) => {
  const {
    target: { files },
  } = event;
  //ํŒŒ์ผ์€ ํ•˜๋‚˜๋งŒ ๋„ฃ์„ ์ˆ˜ ์žˆ๊ฒŒ..^^;;
  const theFile = files[0];
  //console.log(theFile);
  //1. ํŒŒ์ผ๋ฆฌ๋” ์ƒˆ๋กœ ๋งŒ๋“ค๊ณ 
  const reader = new FileReader();
  //3. ํŒŒ์ผ ์ฝ๊ธฐ ๋๋‚˜๋ฉด(reader.onloadend) finishedEvent๋ฅผ ๋ฐ›๋Š”๋‹ค.
  reader.onloadend = (finishedEvent) => {
    //์ฝ˜์†”์— ์ฐ์–ด๋ณด๋ฉด finishedEvent.target.result์— ์ด๋ฏธ์ง€ url์ด ์ƒ์„ฑ๋œ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.
    console.log(finishedEvent);
  };
  //2. ๋ฆฌ๋”์— dataURL๋กœ ์ฝ๊ธฐ ๋ฉ”์„œ๋“œ๋กœ theFile ์ฝ๊ธฐ ์‹œ์ž‘/ ๊ทธ๋Ÿฌ๋ฉด data ์–ป์Œ
  reader.readAsDataURL(theFile);
};
  • console.log(finishedEvent);๋ฅผ ํ•ด๋ณด๋ฉด finishedEvent.target.result์— ์ด๋ฏธ์ง€ ์ฃผ์†Œ๊ฐ€ ์ƒ์„ฑ๋œ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.
    • ์ด ํ…์ŠคํŠธ๋ฅผ ๋ธŒ๋ผ์šฐ์ € ์ฃผ์†Œ์ฐฝ์— ์ž…๋ ฅํ•˜๋ฉด ์ฒจ๋ถ€ํ•œ ์‚ฌ์ง„์ด ๋œฌ๋‹ค!

  • ์ฒจ๋ถ€ํ•œ ์‚ฌ์ง„ ๋ฐ์ดํ„ฐ ๋“ค์–ด์žˆ๋Š” ์œ„์น˜
    : ์ด๋ฒคํŠธ์˜ ํ˜„์žฌ ํƒ€๊ฒŸ์˜ ๊ฒฐ๊ณผ finishedEvent.currentTarget.result
  1. ์ฒจ๋ถ€ํ•œ ์ด๋ฏธ์ง€์˜ url์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก useState()๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ฒจ๋ถ€ํ•œ ์ด๋ฏธ์ง€ ํŒŒ์ผ์ด ์žˆ์œผ๋ฉด ๊ทธ ์ด๋ฏธ์ง€ ํŒŒ์ผ url์„ ์‚ฌ์šฉํ•˜์—ฌ preview img๊ฐ€ ๋œจ๋„๋ก ๋งŒ๋“ค์ž.
//์ฒจ๋ถ€ํŒŒ์ผ readAsDataURL๋กœ ๋ฐ›์€ ๋ฐ์ดํ„ฐ ๋„ฃ์–ด ๋‘๋Š” state
//attachment์— ๋“ค์–ด์˜จ url์€ ์ฒจ๋ถ€ํŒŒ์ผ ๋ฏธ๋ฆฌ๋ณด๊ธฐ img src๋กœ ํ™œ์šฉ
const [attachment, setAttachment] = useState();

//์ƒ๋žต

//file ๋ฏธ๋ฆฌ๋ณด๊ธฐ ์ œ๊ณต
reader.onloadend = (finishedEvent) => {
  //์ฝ˜์†”์— ์ฐ์–ด๋ณด๋ฉด finishedEvent.target.result์— ์ด๋ฏธ์ง€ url์ด ์ƒ์„ฑ๋œ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.
  //console.log(finishedEvent);
  // ์ฒจ๋ถ€ํ•œ ์‚ฌ์ง„ ๋ฐ์ดํ„ฐ ๋“ค์–ด์žˆ๋Š” ์œ„์น˜: ์ด๋ฒคํŠธ์˜ ํ˜„์žฌ ํƒ€๊ฒŸ์˜ ๊ฒฐ๊ณผ
  const {
    currentTarget: { result },
  } = finishedEvent;
  setAttachment(result);
};

//์ƒ๋žต

// attachment๊ฐ€ ์žˆ์„ ๋•Œ๋งŒ img ๋‚˜์˜ค๊ฒŒํ•˜๊ธฐ
{attachment && (<img src={attachment} alt="preview" width="50" height="50" />)}
  1. ํŒŒ์ผ ์—…๋กœ๋“œ ์ทจ์†Œ ๋ฒ„ํŠผ ๋งŒ๋“ค๊ธฐ
    ์ƒ๊ฐ์ด ๋ฐ”๊ปด์„œ ์—…๋กœ๋“œ๋ฅผ ํ•˜๊ณ  ์‹ถ์ง€ ์•Š์„ ๋•Œ ์ฒจ๋ถ€ํ•œ ํŒŒ์ผ์„ ์ทจ์†Œํ•  ๋ฒ„ํŠผ์ด ํ•„์š”ํ•˜๋‹ค!

์ทจ์†Œ ๋ฒ„ํŠผ์„ ๋งŒ๋“ค๊ณ , ์ทจ์†Œ ๋ฒ„ํŠผ ํด๋ฆญ์‹œ(onClick) onClearAttachment ๋ฆฌ์Šค๋„ˆ๊ฐ€ ์‹คํ–‰๋˜๊ฒŒ ํ•œ๋‹ค.
setAttachment()์— null์„ ๋ณด๋‚ด img์˜ ์†Œ์Šค๋ฅผ ์—†์• ์ค€๋‹ค.

//์ฒจ๋ถ€ ์‚ฌ์ง„ ์ทจ์†Œํ•˜๋Š” ๋ฒ„ํŠผ
const onClearAttachment = () => {
  setAttachment(null);
};


//์ƒ๋žต

{attachment && (
            <div>
              <img src={attachment} alt="preview" width="50" height="50" />
              <button onClick={onClearAttachment}>์ทจ์†Œ</button>
            </div>
          )}

  1. setAttachment()์— null์„ ๋ณด๋‚ด ์ฒจ๋ถ€ํ–ˆ๋˜ ์ด๋ฏธ์ง€์˜ url์€ ์ œ๊ฑฐํ–ˆ์ง€๋งŒ ์•„์ง file input์— ์ด๋ฏธ์ง€ ํŒŒ์ผ๋ช…์ด ๋‚จ์•„ ์žˆ๋‹ค.

useRef() ํ›…์„ ์‚ฌ์šฉํ•˜์—ฌ file input ๋ณ€์ˆ˜๋ฅผ ๋งŒ๋“ค๊ณ  file input๊ณผ ์—ฐ๊ฒฐ์‹œ์ผœ์ฃผ๋ฉด ๋œ๋‹ค.

const fileInput = useRef();

const onClearAttachment = () => {
  //1. ์ฒจ๋ถ€ํŒŒ์ผ url ๋„ฃ๋Š” state ๋น„์›Œ์„œ ํ”„๋ฆฌ๋ทฐ img src ์—†์• ๊ธฐ 
  setAttachment(null);
  //2. ์„ ํƒํ–ˆ๋˜ ์ฒจ๋ถ€ํŒŒ์ผ๋ช… ์—†์• ๊ธฐ
  fileInput.current.value = null;
};

//์ƒ๋žต

//์ฒจ๋ถ€ํŒŒ์ผ ์„ ํƒํ•˜๋Š” input
//useRef() ์‚ฌ์šฉ์œ„ํ•ด ref ์†์„ฑ ์ถ”๊ฐ€
<input type="file" accept="image/*" onChange={onFileChange} ref={fileInput}/>
//ํ”„๋ฆฌ๋ทฐ ์ด๋ฏธ์ง€
{attachment && (
            <div>
              <img src={attachment} alt="preview" width="50" height="50" />
              <button onClick={onClearAttachment}>์ทจ์†Œ</button>
            </div>
          )}

์˜ค์ผ€์ด! ์ด์ œ ํŒŒ์ผ์ฒจ๋ถ€๋ฅผ ์ทจ์†Œํ•˜๋ฉด ์ฒจ๋ถ€๋๋˜ ํŒŒ์ผ๋ช…๋„ ์—†์–ด์ง„๋‹ค!

profile
Always have hope๐Ÿ€ & constant passion๐Ÿ”ฅ

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