[React] CSV 파일 생성 후 다운로드 기능 구현

RuLu·2025년 5월 7일
1

React

목록 보기
15/15

백엔드에서 받은 데이터를 ‘프론트’에서 가공해 CSV 로 파일을 생성해야했다.
(사프에서는 백엔드 친구들이 CSV출력 형태로 가공해줬는데,, 보고싶어 얘들아)

전회사에서는 프론트가 먹혀서 무조건 백엔드가 편한대로 까라면 까야했음ㅠ

라이브러리는 react-csv를 사용할거임. << 얘가 csv 변환중에 가장 유명한 듯

https://github.com/react-csv/react-csv

설치

npm install react-csv --save;

사용법

원래 헤더랑, 바디랑 따로 정해서 표 하나를 만들수 있는데 나는 하나의 시트에 여러개의 표를 보여줘야해서 젤 기본 사용법으로 씀

1. 컴포넌트 설명

컴포넌트는 2개를 제공하는데 어떻게 다운로드 할 지를 정한다

  • CSVLink: 클릭으로 csv 다운로드
  • CSVDownload: 마운트되면 바로 다운로드

2. 기본 사용법

나는 클릭해서 다운로드 할 것이기 때문에 CSVLink를 사용한다.

data는 배열형식으로 넣으면 되고 filename은 실제로 다운로드 되었을 때 어떤 이름으로 다운될지이다.

 const csvData:string[][] = [...]
 ...
 <CSVLink data={csvData} filename={'example.csv'} style={{ display: 'none' }} />

data는 행열 그대로 csv 첫번째 칸부터 순서대로 채워짐.

만약 CSVLink에 ref를 사용하고 싶은데 typescript로 작성중이면 아래 타입할당하면 된다.

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

3. 헤더 선언해서 표 만들 때

표의 헤더를 강조하는 스타일을 적용하고 싶을 때는 제목행에 해당하는 배열을 headers Props로 넘긴다.

const headers = ['A', 'B', 'C'];
...
<CSVLink headers={headers} data={csvData} filename={'example.csv'} >
다운로드
</CSVLink>

4. 객체 배열

만약 일반 배열이 아니라 객체배열형식으로 만든다면 헤더의 label값과 데이터의 속성 값을 맞춰서 렌더링 해준다.

const headers = [
	{label: 'ID', key: 'id'},
	{label: 'Name', key: 'name'},
	{label: 'Age', key: 'age'},
]

const csvData = [
	{id: 1, name: 'rulu', age: '20'},
	{id: 2, name: 'alice', age: '21'},
	...
]

<CSVLink headers={headers} data={csvData} filename={'example.csv'} >
다운로드
</CSVLink>

5. 결과

나는 하나의 시트에 여러개의 표가 나와야해서 헤더를 별개로 만들지 않고 이중배열을 이용해서 표 데이터를 채워넣었다.

진짜 코드 더럽고 이상하지만 어쩔 수 없슴.,.ㅠ

각 형태별 csv 표 데이터를 구한 다음에 데이터가 있으면 제목과 함께 표를 렌더링함.

// csv 데이터 만들어서 넣기
  useEffect(() => {
    const { card } = generateCardCSVData(...)
    const { graphChart } = generateGraphChartCSVData(...)
    const { pieChart } = generatePieChartCSVData(...)
    const { heatmapChart } = generateHeatmapChartCSVData(...)

    setCSVData(() => {
      const data: string[][] = []
      let index = 1

      if (!isEmpty(card)) {
        data.push([`${index++}. 요약`], ...card, [''])
      }

      if (!isEmpty(graphChart)) {
        data.push([`${index++}. ${timeUnit === '1h' ? '시간' : '기간'}별 데이터`], ...graphChart, [''])
      }

      if (!isEmpty(pieData)) {
        data.push([`${index++}. 비율`], ...pieChart, [''])
      }

      if (!isEmpty(heatmapChart)) {
        data.push([`${index++}. 히트맵`], ...heatmapChart)
      }

      if (isEmpty(data)) {
        data.push(['다운로드 할 데이터가 없습니다.'])
      }
      return [...data]
    })
  }, [rowCardData, rowChartData])

이런식의 결과물이 나온다.

CSV자체는 안어려웠는데 네트워크 탭 보면서 데이터 구조 분석해서 분기처리하는게 개빡셌음 진짜..
지금 생각해도 스웨거도 명세서도 없이 네트워크 탭으로 개발하라는건 레전드였다

profile
프론트엔드 개발자 루루

0개의 댓글