Reactjs - 이미지 첨부 컴포넌트
728x90
반응형
이미지 첨부 컴포넌트
import React, { useState } from 'react';
import { Button, Box, IconButton, ImageList, ImageListItem, ListSubheader, ImageListItemBar } from '@mui/material';
import CloudUploadIcon from '@mui/icons-material/CloudUpload';
import DeleteIcon from '@mui/icons-material/Delete';
/**
* 이미지 첨부 및 미리보기를 제공하는 컴포넌트
* - 이미지 파일 선택 및 업로드
* - 선택된 이미지 미리보기 표시
* - 개별 이미지 삭제 기능
*/
const ImageAttachButton = () => {
// 첨부된 파일들의 정보를 저장하는 상태
const [attachedFiles, setAttachedFiles] = useState([]);
/**
* 파일 선택 시 실행되는 이벤트 핸들러
* @param {Event} event - 파일 입력 이벤트 객체
*/
const handleFileChange = (event) => {
// FileList 객체를 배열로 변환
const files = Array.from(event.target.files);
// 각 파일에 대한 정보 객체 생성
const newFiles = files.map((file) => ({
name: file.name, // 파일명
size: (file.size / 1024).toFixed(2) + 'KB', // 파일 크기 (KB)
preview: URL.createObjectURL(file), // 미리보기 URL
file: file, // 원본 파일 객체
}));
// 기존 파일 목록에 새로운 파일들을 추가
setAttachedFiles((prevFiles) => [...prevFiles, ...newFiles]);
};
/**
* 파일 삭제 시 실행되는 이벤트 핸들러
* @param {string} fileName - 삭제할 파일의 이름
*/
const handleFileDelete = (fileName) => {
// 지정된 파일명과 일치하지 않는 파일들만 남김
setAttachedFiles((prevFiles) => prevFiles.filter((file) => file.name !== fileName));
};
return (
// 컴포넌트의 최상위 컨테이너
<Box sx={{ width: '100%', maxWidth: 350 }}>
{/* 파일 업로드 버튼 영역 */}
<Box sx={{ padding: 1 }}>
<Button component="label" variant="contained" startIcon={<CloudUploadIcon />} fullWidth>
이미지 첨부
<input
type="file"
hidden
multiple
accept="image/*"
onChange={handleFileChange}
/>
</Button>
</Box>
{/* 이미지 미리보기 목록 */}
<ImageList sx={{ padding: 1, margin: 0 }}>
{attachedFiles.map((file, index) => (
<ImageListItem key={`image_attach_button_list_${index}`}>
{/* 이미지 미리보기 */}
<img
src={file.preview}
alt={file.name}
loading="lazy"
style={{
width: '100%',
height: '100%',
objectFit: 'cover'
}}
/>
{/* 이미지 정보 및 삭제 버튼 바 */}
<ImageListItemBar
title={file.name}
subtitle={file.size}
actionIcon={
<IconButton
sx={{ color: 'rgba(255, 255, 255, 0.54)' }}
aria-label={`info about ${file.name}`}
onClick={() => handleFileDelete(file.name)}
>
<DeleteIcon />
</IconButton>
}
/>
</ImageListItem>
))}
</ImageList>
</Box>
);
};
// App 컴포넌트에서 세로 스크롤과 함께 사용
function App() {
return (
<div style={{
height: '100vh', // 전체 화면 높이
overflowY: 'auto', // 세로 스크롤
}}>
<ImageAttachButton />
<ImageAttachButton />
<ImageAttachButton />
</div>
);
}
export default App;
상세 설명
1. 컴포넌트 구조
- Material-UI(MUI) 컴포넌트를 활용한 이미지 첨부 기능 구현
- 파일 선택 버튼과 선택된 이미지 미리보기 목록으로 구성
- 세로 스크롤이 있는 컨테이너에 배치
2. 주요 기능
파일 선택
input type="file"
요소를 통해 이미지 파일 선택- 다중 선택 가능 (
multiple
속성) - 이미지 파일만 선택 가능 (
accept="image/*"
)
파일 정보 관리
- 파일명, 크기, 미리보기 URL, 원본 파일 객체 저장
- useState를 통한 상태 관리
미리보기 표시
- ImageList 컴포넌트를 사용하여 그리드 형태로 표시
- 각 이미지에 대한 정보(파일명, 크기) 표시
파일 삭제
- 각 이미지 항목에 삭제 버튼 제공
- 파일명을 기준으로 특정 파일 삭제 가능
3. 스크롤 구현
height: '100vh'
로 전체 화면 높이 설정overflowY: 'auto'
로 세로 스크롤 자동 생성- 내용이 화면 높이를 초과할 경우에만 스크롤바 표시
4. 스타일링
- Box 컴포넌트로 전체 너비 제한 (최대 350px)
- 이미지 미리보기는 cover 속성으로 비율 유지
- 삭제 버튼은 반투명한 흰색으로 스타일링
5. 사용 방법
import App from './App';
// 다른 컴포넌트에서 사용
function ParentComponent() {
return <App />;
}
이렇게 구현하면 전체 화면 높이를 사용하면서 내용이 많아질 경우 자동으로 스크롤이 생성되는 이미지 첨부 컴포넌트를 만들 수 있습니다.
728x90
반응형
'개발' 카테고리의 다른 글
Reactjs - useEffect 와 의존성 배열 완벽 가이드 (0) | 2024.11.06 |
---|---|
Reactjs - 드래그 앤 드롭 리스트 구현하기 (0) | 2024.11.06 |
Apache NiFi (0) | 2024.11.01 |
HTTP/2 통신에 대한 정리 (0) | 2024.11.01 |