기록하는 개발자

[React] React+typescript에서 엑셀(csv)다운로드 구현 본문

Web/React

[React] React+typescript에서 엑셀(csv)다운로드 구현

밍맹030 2023. 4. 12. 14:21
728x90

위와 같이 진행 중인 프로젝트에서는 시작, 종료 날짜 입력 후 버튼을 클릭 하면

해당 기간에 대한 직원들의 출근부를 엑셀 파일로 추출해주는 기능이 있다.

 

서버에서 파일을 만들어서 넘겨주는 것보다 프론트에서 작업하는 것이 훨씬 빨랐다.

react-csv라는 훌륭한 라이브러리가 있기 때문이다🥹🥹🥹

 

 

1. 라이브러리 react-csv 다운로드

// npm
npm install react-csv --save;

// yarn
yarn add react-csv

// typescript
npm install --save @types/react-csv

 

2. react-csv의 컴포넌트

react-csv는 CSVLink 와 CSVDownload 두 가지 컴포넌트를 제공한다.

내가 사용한 기능은 사용자가 버튼을 클릭했을 때 csv 파일이 다운로드 되는 CSVLink 이다.

 

  •  CSVLink  :해당 링크를 클릭하면 csv 파일을 다운받을 수 있다.
  •  CSVDownload  : 해당 컴포넌트가 마운트 될 때 자동으로 csv가 다운로드 된다.(엑셀 파일 다운로드가 필요한 시점이 마운트될 때가 아니라면 사용을 권장하지 않는다.)

 

3. react-csv의 props

CSVLink 컴포넌트에서는 여러가지 props 를 사용할 수 있다.

아래의 네 가지 외에도 더 많은 props가 있으니 공식 홈페이지를 참고하자.

 

  • data : csv 파일에서 정보가 들어가는 부분으로 이중배열, 객체 배열, 문자열 형식으로 사용 가능
  • header : csv 파일에서 필드를 지정할 수 있는 부분으로 label과 key값 부여 가능
  • filename : 다운로드 받는 csv 파일의 이름을 지정
  • onClick : 링크를 클릭 시 동기/비동기적으로 작업 수행 시 사용

 

 

4. header와 data

const headers = [
  { label: "이름", key: "name" },
  { label: "전화번호", key: "number" },
  { label: "이메일", key: "email" }
];

const data = [
  { name: "kim", number: "1234", email: "kim@gmail.com" },
  { name: "lee", number: "7890", email: "lee@naver.com" },
  { name: "park", number: "4567", email: "park@daum.com" }
];

header에는 label과 key가 있다.

label은 실제 엑셀 파일 상단에 표시되는 값이다.

key는 해당 필드의 키 값으로, 위와 같이 data 내 { key : value } 형태에서의 key값과 동일해야한다.

 

 

 

사용자 시나리오

시작 날짜와 종료 날짜를 입력 받는다

버튼을 클릭 한다

입력받은 기간에 대한 출근부 데이터를 서버로부터 받아온다

데이터 길이 > 0 : 엑셀 파일을 다운로드 한다.
데이터 길이 == 0  :  window.alert("해당 기간에 출근부 데이터가 없습니다.")

 

ExcelDownload.tsx

날짜를 입력 받고 버튼을 클릭한 뒤에 엑셀 파일을 만들 데이터를 받아오기 때문에

데이터를 모두 받아온 뒤 파일 다운로드가 이루어져야 한다.

 

따라서 CSVLink 컴포넌트에 useRef를 사용해 ref 속성을 넣어주고

데이터가 변경 되면 useEffect를 통해 csvlink의 click() 함수를 실행했다.

import { useState, useRef, useEffect } from "react";
import { CSVLink } from "react-csv";
import { GetExcelDataApi } from "../../../api/workcheck";
import * as type from "../type";

const ExcelDownload = ({ startTime, endTime }: type.ExcelDownloadProps) => {
  const header = [
    { label: "날짜", key: "date" },
    { label: "직원명", key: "name" },
    { label: "근무 시간", key: "time" },
    { label: "근무 형태", key: "workType" },
    { label: "총 근무 시간", key: "totalWorkTime" },
  ];
  
  const [excelData, setExcelData] = useState<Array<type.excelDataProps>>([]);

  const csvLink = useRef<
    CSVLink & HTMLAnchorElement & { link: HTMLAnchorElement }
  >(null);

  useEffect(() => {
    if (excelData.length > 0) {
      csvLink?.current?.link.click();
      setExcelData([]);
    }
  }, [excelData]);

  const getWorkcheckData = async () => {
    if (startTime == "") window.alert("시작일을 입력해주세요");
    else if (endTime == "") window.alert("마감일을 입력해주세요");
    else {
      GetExcelDataApi({ startTime, endTime, setExcelData });
    }
  };

  return (
    <div>
      <button className="getFileButton" onClick={getWorkcheckData}>
        출근부 엑셀 파일 다운로드
      </button>
      <CSVLink
        data={excelData}
        headers={header}
        filename="출근부.csv"
        className="hidden"
        ref={csvLink}
        target="_blank"
      />
    </div>
  );
};

export default ExcelDownload;

 

csvLink의 useRef 선언과 useEffect

- ref 의 current를 사용하여 click 함수 실행 후

의존성 배열에 excelData 있으므로 excelData를 초기화한다.

  const csvLink = useRef<
    CSVLink & HTMLAnchorElement & { link: HTMLAnchorElement }
  >(null);

  useEffect(() => {
    if (excelData.length > 0) {
      csvLink?.current?.link.click();
      setExcelData([]);
    }
  }, [excelData]);

typescript 에서 useRef를 사용하기 위해서는 위와 같이 

 CSVLink & HTMLAnchorElement & { link: HTMLAnchorElement } 

를  type으로 넣어주어야 에러가 발생하지 않는다.

 

 

Header.tsx

import ExcelDownload from "./ExcelDownload";

const Header = () => {
  ...
  return (
    <div>
      ...
      <ExcelDownload startTime={startTime} endTime={endTime}></ExcelDownload>
    </div>
  );
};
export default Header;

 

 

다운로드 받은 엑셀 파일

 

참고

https://developer-talk.tistory.com/106

 

[React]csv 파일로 다운로드

React에서 csv파일로 추출 가능한 Package를 소개합니다. 다운로드 수가 많은 Package부터 작성합니다. react-csv data를 csv파일로 생성합니다. data는 array의 array, object의 array 또는 문자열이 될 수 있습니다

developer-talk.tistory.com

https://stackoverflow.com/questions/65611889/how-to-add-ref-to-csvlink-in-react-typescript

 

How to add ref to CSVLINK in react typescript?

I want to click the CSV download link after the data loaded from the server. I tried all the approaches from https://github.com/react-csv/react-csv/issues/237 const csvLinkRef = React.useRef<CSV...

stackoverflow.com

https://www.npmjs.com/package/react-csv

 

react-csv

Build CSV files on the fly basing on Array/literal object of data . Latest version: 2.2.2, last published: a year ago. Start using react-csv in your project by running `npm i react-csv`. There are 251 other projects in the npm registry using react-csv.

www.npmjs.com

728x90