[React, SheetJS] 엑셀 파일을 업로드하고 테이블로 나타내는 방법

이진우·2024년 7월 22일
0

엑셀 파일을 업로드하고 이를 테이블로 보여줘야하는 요구사항이 생겼습니다.

💻코드

하나의 파일에 해당 기능을 모두 구현한 코드입니다.

import React, {useState} from 'react';
import * as XLSX from 'xlsx';

const ExcelReader: React.FC = () => {
  const [data, setData] = useState<Record<string, string>[]>([]);

  const tableHead = Array.from(data.reduce((acc, cur) => {
    // 키값을 모두 Set 객체에 add
    Object.keys(cur).forEach(k => acc.add(k));
    return acc;
  }, new Set<string>()));

  const handleFileUpload = (e: React.ChangeEvent<HTMLInputElement>) => {
    // 파일을 업로드 했을 때의 처리
    const file = e.target.files?.[0];
    if (file) {
      const reader = new FileReader();
      reader.onload = (evt) => {
        const bstr = evt.target?.result as string;
        const wb = XLSX.read(bstr, {type: 'binary'});
        const wsname = wb.SheetNames[0];
        const ws = wb.Sheets[wsname];
        const data: Record<string, string>[] = XLSX.utils.sheet_to_json(ws);
        setData(data);
      };
      reader.readAsBinaryString(file);
    }
  };

  return (
    <div>
      <input type='file' onChange={handleFileUpload} />
      <table>
        <thead>
        <tr>
          {tableHead.map((value) => (
            <td key={value}>{value}</td>
          ))}
        </tr>
        </thead>
        <tbody>
        {data.map((row, i) => (
          <tr key={i}>
            {tableHead.map((key) => (
              <td key={key}>{row[key] ?? ''}</td>
            ))}
          </tr>
        ))}
        </tbody>
      </table>
    </div>
  );
};

export default ExcelReader;

이 코드는 엑셀 파일을 업로드하고, 그 내용을 웹 페이지의 테이블로 나타내는 기본적인 기능을 구현한 것입니다.

화면은 다음과 같이 나타납니다.

[파일 선택전]


[파일 선택 후]

🤓코드 단계적 설명

React에서 엑셀 파일을 업로드하고, 그 내용을 웹 페이지의 테이블로 나타내는 작업은 다음과 같은 단계로 구성했습니다.:

  1. 파일 업로드: 사용자가 엑셀 파일을 웹 페이지에 업로드할 수 있도록 input 태그를 사용하여 파일 업로드 기능을 구현합니다.

  2. 파일 읽기: 업로드된 파일을 읽기 위해 FileReader 객체를 사용합니다. 이 객체는 웹 애플리케이션에서 비동기적으로 데이터를 읽을 수 있게 해줍니다.

  3. 엑셀 파싱: 'xlsx' 라이브러리를 사용하여 엑셀 파일을 파싱합니다. 이 라이브러리는 엑셀 파일을 JSON 형식으로 변환해줍니다.

  4. 테이블 렌더링: 파싱된 데이터를 기반으로 React 컴포넌트 내에서 테이블을 렌더링합니다.

🌵코드 분리 및 리팩토링

파일 업로드 컴포넌트와 데이터를 보여주는 테이블 컴포넌트를 나누면 다음과 같이 만들 수 있습니다.

// FileUpload.tsx
import React from 'react';
import * as XLSX from 'xlsx';

interface FileUploadProps {
  onFileUpload: (data: Record<string, string>[]) => void;
}

const FileUpload: React.FC<FileUploadProps> = ({onFileUpload}) => {
  const handleFileUpload = (e: React.ChangeEvent<HTMLInputElement>) => {
    const file = e.target.files?.[0];
    if (file) {
      const reader = new FileReader();
      reader.onload = (evt) => {
        const bstr = evt.target?.result as string;
        const wb = XLSX.read(bstr, {type: 'binary'});
        const wsname = wb.SheetNames[0];
        const ws = wb.Sheets[wsname];
        const data: Record<string, string>[] = XLSX.utils.sheet_to_json(ws);
        onFileUpload(data);
      };
      reader.readAsBinaryString(file);
    }
  };

  return <input type='file' onChange={handleFileUpload} />;
};

export default FileUpload;
// DataTable.tsx
import React from 'react';

interface DataTableProps {
  data: Record<string, string>[];
}

const DataTable: React.FC<DataTableProps> = ({data}) => {
  const tableHead = Array.from(data.reduce((acc, cur) => {
    Object.keys(cur).forEach(k => acc.add(k));
    return acc;
  }, new Set<string>()));

  return (
    <table>
      <thead>
      <tr>
        {tableHead.map((value) => (
          <td key={value}>{value}</td>
        ))}
      </tr>
      </thead>
      <tbody>
      {data.map((row, i) => (
        <tr key={i}>
          {tableHead.map((key) => (
            <td key={key}>{row[key] ?? ''}</td>
          ))}
        </tr>
      ))}
      </tbody>
    </table>
  );
};

export default DataTable;
// ExcelReader.tsx
import React, {useState} from 'react';
import FileUpload from './FileUpload';
import DataTable from './DataTable';

const ExcelReader: React.FC = () => {
  const [data, setData] = useState<Record<string, string>[]>([]);

  return (
    <div>
      <FileUpload onFileUpload={setData} />
      <DataTable data={data} />
    </div>
  );
};

export default ExcelReader;
profile
언젠가 보게 된다. 기록하자 😡🔥🔥

0개의 댓글