React | 이미지 추가 기능 만들기

이민재·2023년 2월 18일
0

이미지 추가하기

	// 실제로는 +의 plus_box를 클릭, 동작은 input의 type=[file] 속성을 사용, 이때 input은 보이지 않게 display none 처리.
    
    // input[type=file]은 브라우저에서 직접 로컬 파일을 선택할 수 있게 해준다.
	<input className='input_image' type='file' ref={inputRef} onChange={(event)=>{
          if(event.target.files?.[0]) {
            const reader = new FileReader()
            const file = event.target.files?.[0];
            reader.readAsDataURL(file)
            reader.onloadend = event => {
                setImageList(prev => [...prev, event.target?.result as string])
            }
          }
        }} />
    {
       imaegList.map(img => <ImageBox key={img} src={img}/>)
    }
    <div className='plus_box' onClick={()=>{
       inputRef.current?.click()
    }>
      +
    </div>
        
      

File API

  • FileList: 파일 리스트
  • File: 파일 데이터
  • FileReader: 파일 읽기
  • Blob: 바이트 데이터

File Reader

  • FileReader는 File이나 Blob의 내용을 읽을 수 있게 도와준다.
  • FileReader를 사용하지 않는 이미지의 Local path는 fake path 이므로 사용했다.
  • FileReader에는 4가지 방법으로 파일을 전달할 수 있다.
    - readAsArrayBuffer(file|blob) [ArrayBuffer]
    - readAsBinaryString(file|blob) [0..255 범위의 문자열]
    - readAsDataURL(file|blob) [Base64]
    - readAsText(file|blob) [UTF-16|UTF-8 문자열]
  • FileReader에서 전달 받은 파일을 읽기 성공하면 load EventListner에 등록한 함수가 호출된다.
    - 읽는 상태에 따라 loadstart | progress | loadend | error로 함수 호출

이미지 드래그하기

import {useDropzone} from 'react-dropzone'
import React, { useRef, useState, useCallback } from 'react';
import './App.css';
import ImageBox from './components/ImageBox';

function App() {
  const inputRef = useRef<HTMLInputElement>(null)
  const [imaegList, setImageList] = useState<string[]>([])

  const onDrop = useCallback((acceptedFiles:any) => {
    for(const file of acceptedFiles){
      const reader = new FileReader()
      reader.readAsDataURL(file)
      reader.onloadend = event => {
        setImageList(prev => [...prev, event.target?.result as string])
      }  
    }
  }, [])

  const {getRootProps, getInputProps, open} = useDropzone({onDrop})
  return (
    <div className='container'>
      // UX에 용이하도록 드래그 되는 범위를 전체로 설정
      <div {...getRootProps()}>
        <input {...getInputProps()} />
        <div className={`wrapper_box ${imaegList.length > 0 ? 'row' : '' }`}>
          {
            imaegList.length === 0 &&
            <div className='text'>
              이미지가 없습니다. <br />
              이미지를 추가해주세요.
            </div>
          }
              {
                imaegList.map((img,idx) => <ImageBox key={img+idx} src={img}/>)
              }
            <div className='plus_box' onClick={open}>
              <input className='input_image' type='file' ref={inputRef} />
                    +
                </div>
            </div>    
        </div>
    </div>
  );
}

export default App;

profile
스스로 기억하기 위해서, 기록해요

0개의 댓글