-
다양한 파일 확장자 파일 미리보기 지원하기React.js & Next.js 2023. 4. 5. 21:25
목차
- 들어가며
- text, image, pdf, video 대응하기
- 리팩터링 with ChatGPT
들어가며
실무에서 폼 양식을 작성할 때, 다양한 타입의 파일을 지원하게 됩니다. 아쉽게도 우리는 단순히 객체로만 파일을 가지고 있는 것이 아닌, UX를 위해 파일의 미리 보기를 요구받을 수 있습니다. 따라서 이번에는 다양한 확장자 파일에 대하여 미리 보기를 지원하는 방법 및 로직을 알아봅니다.
text, image, pdf, video 대응하기
import React, { useState } from 'react'; const Test = () => { const [text, setText] = useState<string>(''); const handleFileInputChange = (event: React.ChangeEvent<HTMLInputElement>): void => { const file = event.target.files?.[0]; if (!file) return; const { type } = file; if (type === 'text/plain') { // Handle text file const reader = new FileReader(); reader.onload = (event: ProgressEvent<FileReader>) => { setText(event.target?.result as string); }; reader.readAsText(file); } else if (type.startsWith('image/')) { // Handle image file const url = URL.createObjectURL(file); console.log('--url:', url) setText( `<img src="${url}" alt="${file.name}" style="width:auto; max-height:200px" />` ); } else if (type === 'application/pdf') { // Handle PDF file const url = URL.createObjectURL(file); console.log('--url:', url) setText( `<embed src="${url}" type="application/pdf" style="width:auto; height:200px" />` ); } else if (type === 'video/mp4' || type === 'video/quicktime') { const url = URL.createObjectURL(file); setText(`<video src="${url}" controls style="width:auto; height:200px" />`); } else { console.log('-- type: ', type); // Handle other file types setText(`Unsupported file type: ${type} about ${file.name}`); } }; return ( <div> <input type="file" onChange={handleFileInputChange} /> <p dangerouslySetInnerHTML={{ __html: text }} /> </div> ); }; export default Test;
URL.createObjectURL( )
URL.createObjectURL() 메서드는 지정된 객체를 나타내는 URL을 생성합니다. 이 URL은 해당 객체를 나타내는 URL이지 실제 파일의 위치가 아닙니다. 이 URL을 사용하면 브라우저에서 객체를 로드 및 표시할 수 있습니다. 이 메서드를 사용하여 Blob, File, MediaSource, BlobEvent 등과 같은 객체를 나타내는 URL을 생성할 수 있습니다.
Blob이란, 파일과 같은 큰 데이터를 처리할 때 사용하는 객체입니다. URL.createObjectURL() 메소드는 Blob 객체를 인자로 넘겨주면 해당 파일을 나타내는 URL을 생성합니다. 이를 통해 브라우저에서 파일을 로드 및 표시할 수 있습니다. Blob 객체는 일반적으로 파일 업로드, 이미지 및 비디오 처리 등에 사용됩니다.
url
-- url: blob:<http://localhost:3000/ad078bd3-a5e7-49c7-966b-fde8e0018f9b>
리팩터링 with ChatGPT
case 1: Refactoring with using switch case statement
import React, { useState } from 'react'; const Test = () => { const [text, setText] = useState<string>(''); const handleFileInputChange = (event: React.ChangeEvent<HTMLInputElement>): void => { const file = event.target.files?.[0]; if (!file) { return; } const { type } = file; const handleTextFile = (file: File) => { const reader = new FileReader(); reader.onload = (event: ProgressEvent<FileReader>) => { setText(event.target?.result as string); }; reader.readAsText(file); }; const handleImageFile = (file: File) => { const url = URL.createObjectURL(file); setText(`<img src="${url}" alt="${file.name}" style="width:auto; max-height:200px" />`); }; const handlePdfFile = (file: File) => { const url = URL.createObjectURL(file); setText(`<embed src="${url}" type="application/pdf" style="width:auto; height:200px" />`); }; const handleVideoFile = (file: File) => { const url = URL.createObjectURL(file); setText(`<video src="${url}" controls style="width:auto; height:200px" />`); }; const handleUnsupportedFile = (file: File) => { console.log('-- type: ', type); setText(`Unsupported file type: ${type} about ${file.name}`); }; switch (type) { case 'text/plain': handleTextFile(file); break; case 'image/jpeg': case 'image/png': case 'image/gif': handleImageFile(file); break; case 'application/pdf': handlePdfFile(file); break; case 'video/mp4': case 'video/quicktime': handleVideoFile(file); break; default: handleUnsupportedFile(file); break; } }; return ( <div> <input type='file' onChange={handleFileInputChange} /> <p dangerouslySetInnerHTML={{ __html: text }} /> </div> ); }; export default Test;
이 코드에서는,
- 더 나은 가독성과 유지관리를 위해 다른 파일 형식을 처리하기 위한 논리를 별도의 기능으로 추출했습니다
- 파일 형식에 따라 호출할 적절한 함수를 결정하기 위해 'switch' 문을 추가했습니다
- 더 나은 형식 안전을 위해 함수와 변수에 타입스크립트 주석을 추가했습니다
case 2: Make short with using Record
import React, { useState } from 'react'; const Test = () => { const [text, setText] = useState<string>(''); const handleFileInputChange = async (event: React.ChangeEvent<HTMLInputElement>): Promise<void> => { const file = event.target.files?.[0]; if (!file) return; const { type } = file; const url = URL.createObjectURL(file); const fileHandlers: Record<string, () => void> = { 'text/plain': () => setText(await file.text()), 'image/jpeg': () => setText(`<img src="${url}" alt="${file.name}" style="width:auto; max-height:200px" />`), 'image/png': () => setText(`<img src="${url}" alt="${file.name}" style="width:auto; max-height:200px" />`), 'image/gif': () => setText(`<img src="${url}" alt="${file.name}" style="width:auto; max-height:200px" />`), 'application/pdf': () => setText(`<embed src="${url}" type="application/pdf" style="width:auto; height:200px" />`), 'video/mp4': () => setText(`<video src="${url}" controls style="width:auto; height:200px" />`), 'video/quicktime': () => setText(`<video src="${url}" controls style="width:auto; height:200px" />`), default: () => setText(`Unsupported file type: ${type} about ${file.name}`), }; const handler = fileHandlers[type] || fileHandlers.default; handler(); }; return ( <div> <input type='file' onChange={handleFileInputChange} /> <p dangerouslySetInnerHTML={{ __html: text }} /> </div> ); }; export default Test;
이 코드의 단축 버전에서는
- 딕셔너리 오브젝트를 사용하여 파일 형식을 해당 처리 함수에 매핑함으로써 서로 다른 파일 형식을 처리하는 논리를 단순화했습니다
- 파일 리더 API를 이용해 텍스트 파일을 처리하는 비동기 기능도 추가했습니다
- 또한 다양한 이미지 파일 형식을 처리하기 위한 코드를 통합하여 'setText' 호출을 단축했습니다
결과 보기
레퍼런스
URL.createObjectURL() - Web API | MDN
'React.js & Next.js' 카테고리의 다른 글
구글 애널리틱스 (GA4) for developers (3) 2023.07.16 리액트에서 다중의 동적 폼 처리하기 (0) 2023.06.15 input image 미리보기 구현하기 (0) 2023.03.31 빠르게 시작하는 드래그 앤 드롭 (0) 2023.03.26 Next Image load super slow (1) 2023.01.04