Wyszukiwanie w witrynie

javascript - Ładowanie danych asynchronicznie i pobieranie danych CSV po kliknięciu jest o jeden krok za najnowszymi pobranymi danymi


Używając pakietu react-csv, wczytuję dane asynchronicznie, a następnie próbuję pobrać pobrane dane z serwera jednym kliknięciem. Problem, z którym się obecnie mierzę, polega na tym, że kliknięcie jest o krok za aktualnym stanem. Kiedy komponent renderuje się po raz pierwszy, pobiera pusty plik CSV, a przy drugim kliknięciu pobiera dane z poprzedniego pobrania, a nie z aktualnego/najnowszego pobrania. To jest ta sama sytuacja, która jest opisana tutaj, ale rozwiązanie tam wspomniane nie zadziałało w moim przypadku.

Oto kod, nad którym pracuję:

const [newData, setNewData] = useState([]);
const csvLink = React.createRef();

const csvExport = (
  <div>
    <Button className="pull-right title-button" onClick={getData}>
      CSV Export
    </Button>
    <CSVLink data={newData} headers={headers} target="_blank" ref={csvLink}></CSVLink>
  </div>
);

const getData = async () => {
  await getRetailLinkOutcomes(auth, startDate, endDate, 0, 0, filters, sort, sortDirection, false).then((response) => {
    setNewData(response.records);
    csvLink.current.link.click();
  });
};

Odpowiedź #1

Miałem ten sam problem, rozwiązałem go, nie używając <CSVLink asyncOnClick> (co było koszmarem z Typescriptem i po prostu nie działało, chyba że użytkownik kliknął przycisk dwukrotnie lub dane były wstępnie załadowane)

Aby obsłużyć pobieranie danych asynchronicznych, możesz użyć zwykłego przycisku do inicjowania asynchronicznego pobierania oraz warunkowo renderowanego przycisku, który pobiera plik CSV

const [initiateDownload, setInitiateDownload] = useState(false)
const [csvRows, setCsvRows] = useState([])

const fetchCsvData = async () => {
  const response = await fetchData()
  setCsvRows(response.data)
}

useEffect(() => {
  if (csvRows.length) {
    setInitiateDownload(true)
  }
}, [csvRows])

useEffect(() => {
  // Enables user to download data more than once
  if (initiateDownload) {
    setInitiateDownload(false)
  }
}, [initiateDownload])

return (
  <button onClick={fetchCsvData}>Export CSV</button>
  {initiateDownload && (
    <CSVDownload
      data={csvRows}
      headers={csvHeaders}
      target="_blank"
    />
  )}
)

Odpowiedź #2

Rozwijając więcej tego, co N.A wspomniał w komentarzach:

  const [data, setData] = useState([])
  const [headers, setHeaders] = useState([])
  const excelRef = useRef()

Funkcja do pobierania danych :

    function requestAllHistory () {
        console.log('requesting excel history')
        requestAllHistoryForExcel(function (response, error) {
        // data and headers fetched
        setData(data)
        setHeaders(headers)
    })
}

We wnętrzu useEffect

  useEffect(() => {
    if (headers.length > 0) {
      console.log('ExportExcel useEffect', headers)
      excelRef.current.link.click()
    }
  }, [headers])

Link CSV nie powinien być wyświetlany w interfejsie użytkownika (display:'none')

   return (
    <span>
      <button
        type='button'
        className='btn btn-lg btn-dark'
        onClick={() => requestAllHistory()}
      >
        <span> Export to Excel </span>
        <span className='download'></span>
      </button>
      <CSVLink
        data={data}
        headers={headers}
        filename={filename}
        ref={excelRef}
        className='hiddenExcel'
        target='_blank'
      ></CSVLink>
    </span>
  )