본문 바로가기
React

[React] 드래그앤 드롭으로 파일 업로드 하기

by teamnova 2023. 11. 22.


오늘은 React를 사용하여 파일 업로드 기능을 갖춘 컴포넌트를 만들어보겠습니다. 이 컴포넌트는 파일 선택, 드래그 앤 드롭, 그리고 서버로 파일을 업로드할 수 있는 기능을 제공합니다. 

파일 업로드 컴포넌트 생성

먼저, React 프로젝트에서 `UploadBox` 컴포넌트를 생성합니다. 이 컴포넌트는 파일을 선택하거나 드래그하여 업로드하고, 선택한 파일의 정보를 표시합니다.

import React, { useState } from 'react';

const UploadBox = ({ socket }) => {
  // 상태 변수 초기화
  const [isActive, setActive] = useState(false);
  const [uploadedInfo, setUploadedInfo] = useState(null);

  // ... (이하 코드 생략)
};

export default UploadBox;


'UploadBox' 컴포넌트 설명

- `useState` 함수를 사용하여 상태 변수 `isActive`와 `uploadedInfo`를 초기화합니다.
- `handleDragStart`, `handleDragEnd`, `handleDragOver`, `setFileInfo`, `handleDrop`, `handleUpload`, `handleSubmit` 등의 함수가 들어 있으며, 파일 업로드와 관련된 로직을 처리합니다.

파일 선택 및 드래그 앤 드롭

 

`UploadBox` 컴포넌트는 파일을 선택하거나 드래그하여 업로드할 수 있는 기능을 제공합니다. 

<label
  className={`preview${isActive ? ' active' : ''}`}
  onDragEnter={handleDragStart}
  onDragOver={handleDragOver}
  onDragLeave={handleDragEnd}
  onDrop={handleDrop}
>
  <input type="file" className="file" onChange={handleUpload} />
  {/* 파일 정보 표시 */}
</label>


- `label` 요소 내부에는 파일 선택(input)과 드래그 앤 드롭 이벤트 핸들러가 있습니다.
- 파일 선택(input)은 `onChange` 이벤트로 `handleUpload` 함수와 연결되어 파일을 선택하면 해당 파일 정보를 설정합니다.
- 드래그 앤 드롭 이벤트는 `handleDragStart`, `handleDragOver`, `handleDragEnd`, `handleDrop` 함수와 연결되어 파일을 드래그할 때 활성 상태를 표시하고 파일 정보를 설정합니다.

 

파일전송

파일을 선택하고 "파일 전송" 버튼을 누르면 파일 데이터를 서버로 전송하는 기능을 구현합니다.

<button onClick={handleSubmit}>파일 전송</button>


- "파일 전송" 버튼은 `onClick` 이벤트로 `handleSubmit` 함수와 연결되어 있습니다.
- `handleSubmit` 함수에서는 선택한 파일 데이터를 서버로 전송할 수 있도록 상황에 맞게 코드를 작성해 줍시다.

파일정보표시

선택한 파일의 정보를 표시하는 부분입니다.

 

{uploadedInfo && <FileInfo uploadedInfo={uploadedInfo} />}



- `uploadedInfo` 상태 변수가 설정되면 `FileInfo` 컴포넌트가 렌더링되어 파일 정보를 표시합니다.

로고 및 안내메세지

파일을 선택하지 않았을 때 화면에 보이는 로고와 안내 메시지를 포함합니다.

 

{!uploadedInfo && (
  <>
    <Logo />
    <p className="preview_msg">클릭 혹은 파일을 이곳에 드롭하세요.</p>
    <p className="preview_desc">파일당 최대 3MB</p>
  </>
)}



- `uploadedInfo`가 없을 때, 즉 파일을 선택하지 않은 상태에서는 로고와 안내 메시지가 표시됩니다.

`UploadBox` 컴포넌트를 사용하면 React 애플리케이션에서 파일 업로드를 구현할 수 있습니다. 파일 선택, 드래그 앤 드롭, 파일 정보 표시, 파일 전송 등의 기능을 제공하며, 서버로 파일을 전송하는 부분은 서버 측에서 구현해야 합니다.

다음은 컴포넌트 전체 코드 입니다.

import React from 'react';
import ReactDOM from 'react-dom';

const { useState } = React;

const FileInfo = ({ uploadedInfo }) => (
  <ul className="preview_info">
    {Object.entries(uploadedInfo).map(([key, value]) => (
      <li key={key}>
        <span className="info_key">{key}</span>
        <span className="info_value">{value}</span>
      </li>

    ))}
  </ul>
);

const Logo = () => (
  <svg className="icon" x="0px" y="0px" viewBox="0 0 24 24">
    <path fill="transparent" d="M0,0h24v24H0V0z"/>
    <path fill="#000" d="M20.5,5.2l-1.4-1.7C18.9,3.2,18.5,3,18,3H6C5.5,3,5.1,3.2,4.8,3.5L3.5,5.2C3.2,5.6,3,6,3,6.5V19  c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V6.5C21,6,20.8,5.6,20.5,5.2z M12,17.5L6.5,12H10v-2h4v2h3.5L12,17.5z M5.1,5l0.8-1h12l0.9,1  H5.1z"/>
  </svg>
);

const UploadBox = () => {
  const [isActive, setActive] = useState(false);
  const [uploadedInfo, setUploadedInfo] = useState(null);

  const handleDragStart = () => setActive(true);
  const handleDragEnd = () => setActive(false);
  const handleDragOver = (event) => {
    event.preventDefault();
  };

  const setFileInfo = (file) => {
    const { name, size: byteSize, type } = file;
    const size = (byteSize / (1024 * 1024)).toFixed(2) + 'mb';
    setUploadedInfo({ name, size, type }); // name, size, type 정보를 uploadedInfo에 저장
  };

  const handleDrop = (event) => {
    event.preventDefault();
    setActive(false);

    const file = event.dataTransfer.files[0];
    setFileInfo(file);
  };

  const handleUpload = ({ target }) => {
    const file = target.files[0];
    setFileInfo(file);
  };

  const handleSubmit = () => {
    // 서버로 파일을 전송하는 로직을 구현

    }

  };
  
  return (
    <label
      className={`preview${isActive ? ' active' : ''}`}
      onDragEnter={handleDragStart}
      onDragOver={handleDragOver}
      onDragLeave={handleDragEnd}
      onDrop={handleDrop}
    >
      <input type="file" className="file" onChange={handleUpload} />
      {uploadedInfo && <FileInfo uploadedInfo={uploadedInfo} />}
      {uploadedInfo && (
    <button onClick={handleSubmit}>파일 전송</button>
  )}
      {!uploadedInfo && (
        <>
          <Logo />
          <p className="preview_msg">클릭 혹은 파일을 이곳에 드롭하세요.</p>
          <p className="preview_desc">파일당 최대 3MB</p>
        </>
      )}
    </label>
  );
};

// ReactDOM.render(<UploadBox />, document.getElementById('root')); 

export default UploadBox;