> Hello World !!!

     

@syaku

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. 주요 기능

  1. 파일 선택

    • input type="file" 요소를 통해 이미지 파일 선택
    • 다중 선택 가능 (multiple 속성)
    • 이미지 파일만 선택 가능 (accept="image/*")
  2. 파일 정보 관리

    • 파일명, 크기, 미리보기 URL, 원본 파일 객체 저장
    • useState를 통한 상태 관리
  3. 미리보기 표시

    • ImageList 컴포넌트를 사용하여 그리드 형태로 표시
    • 각 이미지에 대한 정보(파일명, 크기) 표시
  4. 파일 삭제

    • 각 이미지 항목에 삭제 버튼 제공
    • 파일명을 기준으로 특정 파일 삭제 가능

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