개요
FileReader
API를 사용하여 선택된 파일을 Data URL로 변환하고, 이를 이미지 요소의 src
속성에 할당하여 미리보기를 할 수 있다.
주요 기능
- 즉시 미리보기: 파일 선택과 동시에 이미지 미리보기 제공
- 파일 유효성 검사: 이미지 파일만 허용
- 에러 처리: 파일 읽기 실패 시 적절한 에러 메시지 표시
- 메모리 효율성: Data URL을 사용하여 별도의 서버 요청 없이 미리보기
구현 방법
1. FileReader를 사용한 파일 읽기
FileReader
API의 readAsDataURL()
메서드를 사용하여 파일을 Base64 인코딩된 Data URL로 변환한다.
2. 비동기 처리
파일 읽기는 비동기 작업이므로 Promise를 사용하여 처리한다.
3. 상태 관리
React의 useState
를 사용하여 미리보기 이미지 URL을 관리한다.
Usage
tsx1import 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}
주의사항
- 메모리 사용량: 큰 이미지 파일의 경우 Data URL이 메모리를 많이 사용할 수 있다.
- 파일 크기 제한: 적절한 파일 크기 제한을 설정하는 것이 좋다.
- 브라우저 호환성:
FileReader
API는 모든 모던 브라우저에서 지원된다.
- 보안: Data URL은 민감한 정보를 포함할 수 있으므로 주의가 필요하다.