본문 바로가기

카테고리 없음

리액트 타입스크립트 File Drag & Drop

1. FileReader에서 readAsDataURL() 메서드는 File 타입 객체를 읽어서 Base64로 인코딩된 문자열 형태의 데이터를 제공한다. File 객체는 바이너리 데이터를 Blob으로 저장하며, 이 데이터를 readAsDataURL() 메서드를 통해 문자열로 변환하여 이미지 등의 데이터를 처리할 수 있게 해준다.

 

// Blob 타입의 파일을 읽어 Base64로 인코딩된 문자열을 반환하는 함수
export const imageFileReaderP = (file: Blob) =>
  new Promise<string>((resolve, reject) => {
    // FileReader 객체 생성
    const fileReader = new FileReader()
    
    // onload는 파일을 성공적으로 읽었을 때 실행되는 이벤트 핸들러
    fileReader.onload = (e: ProgressEvent<FileReader>) => {
      // 파일을 Base64로 인코딩한 결과를 가져옴
      const result = e.target?.result 

      // 인코딩 결과가 문자열이면 resolve로 반환, 그렇지 않으면 reject로 에러 반환
      if (result && typeof result === 'string') resolve(result)
      else reject(new Error(`imageFileReaderP: can't read image file`))
    }
    
    // Blob 또는 File 객체를 읽어 Base64 인코딩된 문자열로 변환
    fileReader.readAsDataURL(file)
  })

 

 

2.드래그드롭으로 이미지를 넣거나 클릭해서 파일창을 열수 있게 만든코드

 

base64는 인코딩하는데 시간이 걸리므로 비동기 Promise처리

 

export default function FileDrop() {
  const [imageUrls,setImageUrls] = useState<string[]>([])
  const [error, setError] = useState<Error | null>(null)
  const [loading,toggleLoading] = useToggle(false)

  const inputRef = useRef<HTMLInputElement>(null)
  const onDivClick = useCallback(() => inputRef.current?.click(),[])

  const makeImageUrls = useCallback((files: File[]) => {
    // 유사 배열 객체를 배열로 변환 (Array.from())
    // 각 파일을 Base64로 인코딩된 URL로 변환
    const promises = Array.from(files).map(imageFileReaderP)
    
   
    // 로딩 상태 시작
    toggleLoading() 
    // Base64 인코딩은 시간이 걸리므로, 비동기 작업을 Promise로 처리
    Promise.all(promises)
      // 새로운 URL 배열과 기존 imageUrls 배열을 합침
      .then(urls => setImageUrls(imageUrls => [...urls, ...imageUrls]))
      // 에러가 발생하면 에러 상태로 설정
      .catch(setError) 
      // 로딩 상태 종료
      .finally(toggleLoading) 
  }, [toggleLoading])

 

 

*주석설명 참고

 

// 여러개의 파일들을 선택할 수 있다.
  const onInputChange = useCallback((e:ChangeEvent<HTMLInputElement>) =>{
    setError(null)
    const files = e.target.files
    files && makeImageUrls(Array.from(files))
  },[makeImageUrls])

  const onDivDragOver = useCallback((e:DragEvent) => e.preventDefault(),[])

  // 이미지를 떨어트려 파일을 추가할 수 있게함 
  const onDivDrop = useCallback((e:DragEvent) => {
    e.preventDefault()
    setError(null)
    const files = e.dataTransfer?.files
    files && makeImageUrls(Array.from(files))},[makeImageUrls]
   
  )

 

 

 

 

map을 사용해 배열을 반복해서 새로운 배열로 반환

 

    const images = useMemo(() => (
     imageUrls.map((url,index) => (
      <Div key={index} src={url} className='m-2 bg-transparent bg-center bg-no-repeat bg-contain' 
      width='5rem' height='5rem'
      />
     ))
    ),[imageUrls]
  )
console.log(images)
    return (
      <section className="mt-4">
        <Title>FileDrop</Title>
         {/* 오류가 발생한 경우 오류 메시지를 표시 */}
        {error && (
          <div className="p-4 mt-4 bg-red-200">
            <p className="text-3xl text-red-500 text-bold">{error.message}</p>
          </div>
        )}
  
        <div onClick={onDivClick} className="w-full mt-4 bg-gray-200 border border-gray-500">
          {/* 파일 업로드 중 로딩 상태를 표시 */}
          {loading && (
            <div className="flex imtes-center justify-center">
              <Button className="btn-circle loading"></Button>
            </div>
          )}
          <div onDragOver={onDivDragOver} onDrop={onDivDrop}
            className="flex flex-col items-center justify-center h-40 cursor-pointer">
              <p className="text-3xl font-bold">drop images or click me</p>
          </div>
          <input ref={inputRef} onChange={onInputChange} multiple className="hidden" type="file" accept="image/*" />
        </div>
        <div className="flex flex-wrap justify-center">{images}</div>
      </section>
    )
}

 

 

 

결과 화면

 

클릭하면 파일창이 뜬다 이때 여러 이미지를 선택할 수 있고 드래그해서 이미지를 넣을 수 있다.

 

 

 

유사배열객체 Array.from()을 사용해 배열로 변환 (이미지 두개를 넣었다)

 

 

base64로 인코딩이 되어있다

 

 

 

 

 

 

참고한 책입니다

 

https://www.yes24.com/Product/Goods/125567157

 

Do it! 리액트로 웹앱 만들기 with 타입스크립트 - 예스24

“프런트엔드 개발자 채용 공고에서 인기 있는 자격 요건은 모두 갖췄다!” 최신 웹 개발 트렌드를 반영하고 실무 코드로 가득 채운 ‘리액트 전문서’ 등장! 이 책은 많은 기업에서 우대하는

www.yes24.com