<Welcome! />

앱 설치하기

더 나은 사용자 경험을 위해 앱을 설치해보세요!

이미지 업로드 시 미리보기 기능 만들기

2024-09-27

4

개요

FileReader API를 사용하여 선택된 파일을 Data URL로 변환하고, 이를 이미지 요소의 src 속성에 할당하여 미리보기를 할 수 있다.

주요 기능

  • 즉시 미리보기: 파일 선택과 동시에 이미지 미리보기 제공
  • 파일 유효성 검사: 이미지 파일만 허용
  • 에러 처리: 파일 읽기 실패 시 적절한 에러 메시지 표시
  • 메모리 효율성: Data URL을 사용하여 별도의 서버 요청 없이 미리보기

구현 방법

1. FileReader를 사용한 파일 읽기

FileReader API의 readAsDataURL() 메서드를 사용하여 파일을 Base64 인코딩된 Data URL로 변환한다.

2. 비동기 처리

파일 읽기는 비동기 작업이므로 Promise를 사용하여 처리한다.

3. 상태 관리

React의 useState를 사용하여 미리보기 이미지 URL을 관리한다.

Usage

tsx
1import React, { useState } from 'react';
2
3const readFileAsDataURL = (file: File): Promise<string> => {
4  return new Promise((resolve, reject) => {
5    const reader = new FileReader();
6    reader.onload = (event) => resolve(event.target?.result as string);
7    reader.onerror = () => reject(new Error('파일을 불러오는데 실패했습니다.'));
8    reader.readAsDataURL(file);
9  });
10};
11
12export default function ImageUploader() {
13  const [imageUrl, setImageUrl] = useState<string | null>(null);
14  const [isLoading, setIsLoading] = useState(false);
15  const [error, setError] = useState<string | null>(null);
16
17  const handleUpload = async (e: React.ChangeEvent<HTMLInputElement>) => {
18    const file = e.target.files && e.target.files[0];
19
20    if (!file) return;
21
22    // 파일 타입 검증
23    if (!file.type.startsWith('image/')) {
24      setError('이미지 파일만 업로드 가능함.');
25      return;
26    }
27
28    // 파일 크기 검증 (5MB 제한)
29    if (file.size > 5 * 1024 * 1024) {
30      setError('파일 크기는 5MB 이하여야함.');
31      return;
32    }
33
34    setIsLoading(true);
35    setError(null);
36
37    try {
38      const dataUrl = await readFileAsDataURL(file);
39      setImageUrl(dataUrl);
40    } catch (err) {
41      setError(err instanceof Error ? err.message : '알 수 없는 오류 발생');
42    } finally {
43      setIsLoading(false);
44    }
45  };
46
47  const handleRemove = () => {
48    setImageUrl(null);
49    setError(null);
50    // input 값 초기화
51    const fileInput = document.querySelector(
52      'input[type="file"]',
53    ) as HTMLInputElement;
54    if (fileInput) fileInput.value = '';
55  };
56
57  return (
58    <div className="image-uploader">
59      <div className="upload-section">
60        <input
61          type="file"
62          accept="image/*"
63          onChange={handleUpload}
64          disabled={isLoading}
65        />
66        {isLoading && <p>이미지를 불러오는 중...</p>}
67        {error && <p className="error">{error}</p>}
68      </div>
69
70      {imageUrl && (
71        <div className="preview-section">
72          <img
73            src={imageUrl}
74            alt="미리보기"
75            style={{ maxWidth: '100%', maxHeight: '300px' }}
76          />
77          <button onClick={handleRemove}>제거</button>
78        </div>
79      )}
80    </div>
81  );
82}

주의사항

  1. 메모리 사용량: 큰 이미지 파일의 경우 Data URL이 메모리를 많이 사용할 수 있다.
  2. 파일 크기 제한: 적절한 파일 크기 제한을 설정하는 것이 좋다.
  3. 브라우저 호환성: FileReader API는 모든 모던 브라우저에서 지원된다.
  4. 보안: Data URL은 민감한 정보를 포함할 수 있으므로 주의가 필요하다.