HOW-TO GUIDES

react-csv에서 onClick 시점에 async로 데이터를 받아 오는 방법

encredible 2021. 9. 16. 17:52

react-csv는 주어진 데이터를 csv 파일로 만들어주는 라이브러리입니다.(https://www.npmjs.com/package/react-csv)

array의 array 형태나 object의 array 형태의 데이터 등을 손쉽게 파일로 만들어서 다운로드 받을 수 있게 해줍니다. 그러나, 이 라이브러리의 단점이 있습니다. 데이터가 생성되는 시점에 데이터를 가지고 다운로드 하게 된다는 점입니다.

<CSVLink data={csvData}>Download me</CSVLink>;

이런 방식으로 컴포넌트를 만들고 csvData로 데이터를 집어 넣습니다.

위의 npm 링크를 들어가보면,

import { CSVLink } from "react-csv";

<CSVLink
  data={data}
  asyncOnClick={true}
  onClick={(event, done) => {
    axios.post("/spy/user").then(() => {
      done(); // REQUIRED to invoke the logic of component
    });
  }}
>
  Download me
</CSVLink>;

이와 같은 방식으로 onClick 시에 post를 한 후에 done 이전에 data값을 업데이트 해주면 될 것처럼 되어 있지만, 실상은 잘 동작하지 않습니다.

이 문제를 해결하기 위해서는 아래와 같은 방법을 사용해야 합니다.(참고: https://stackoverflow.com/questions/53504924/reactjs-download-csv-file-on-button-click)

import React, { useState, useRef } from 'react'
import { Button } from 'react-bootstrap'
import { CSVLink } from 'react-csv'
import api from 'services/api'

const MyComponent = () => {
  const [transactionData, setTransactionData] = useState([])
  const csvLink = useRef() // setup the ref that we'll use for the hidden CsvLink click once we've updated the data

  const getTransactionData = async () => {
    // 'api' just wraps axios with some setting specific to our app. the important thing here is that we use .then to capture the table response data, update the state, and then once we exit that operation we're going to click on the csv download link using the ref
    await api.post('/api/get_transactions_table', { game_id: gameId })
      .then((r) => setTransactionData(r.data))
      .catch((e) => console.log(e))
    csvLink.current.link.click()
  }

  // more code here

  return (
  // a bunch of other code here...
    <div>
      <Button onClick={getTransactionData}>Download transactions to csv</Button>
      <CSVLink
         data={transactionData}
         filename='transactions.csv'
         className='hidden'
         ref={csvLink}
         target='_blank'
      />
    </div>
  )
}

이 방법을 요약하자면, Button 에서 async 오퍼레이션을 대신 처리해준 후에 CSVLink의 click()을 호출하는 것입니다. 먼저 getTransactionData를 보면 async로 선언된 함수입니다. 여기서 post를 호출하여 transaction_table 정보를 가져온 후에 가져온 정보를 setTransactionData로 저장을 합니다. await를 사용하여 이 과정이 모두 끝난 후에 csvLink.current.link.click()을 호출하여 setTransactionData를 통해 set된 정보를 csv로 변환시켜 가져옵니다.