Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

asyncOnClick = true together with onClick just doesnt work #350

Open
logemann opened this issue Oct 12, 2022 · 9 comments
Open

asyncOnClick = true together with onClick just doesnt work #350

logemann opened this issue Oct 12, 2022 · 9 comments

Comments

@logemann
Copy link

Something is definitely off with the asyncOnClick. After my supabase call (which invokes a REST call), the file is instantly downloaded (see the logging line) with the empty state because the data will be put in the state in the next line. So even before i call done(true|false), this thing downloads.

I dont even know how this can be. I am just doing an API call and that triggers the download. And no, there is no throwing of an exception in the api call or anything like that.

Has anyone experienced something similar? Its super weird.

  const getExports = async (event, done) => {
  let { data: exports, error } = await supabase
        .from("names_x")
        .select("*")
        .eq("export_id", exportId);
   console.log("Now the file gets downloaded");
   setCsvData(myInserts); // here i put data in state variable
   done(true);
 }

<CSVLink
                    data={dataFromState()}
                    asyncOnClick={true}
                    onClick={getExports}
>
   Download 
</CSVLink>
@logemann logemann changed the title asyncOnClick = true together with onClick just doenst work asyncOnClick = true together with onClick just doesnt work Oct 12, 2022
@derekbwarren
Copy link

I am having the same issue. @abdennour any chance this can get fixed?

@spencerjsmall
Copy link

I'm having the same issue. Of course, when the download gets triggered a second (and third, fourth, etc.) time, the data gets loaded properly because it's been set to the state variable. Only workaround I can think of is to have a dummy wrapper button that makes the API call and sets it to the state, before programmatically triggering CSVLink.

@spencerjsmall
Copy link

export default function DownloadBtn() {
  const [csv, setCSV] = useState({ data: null, fileName: "" });
  const csvLink = useRef(null);

  const exportToCsv = async (layer) => {
    const response = await fetch(`/actions/${layer.id}/csv`, {
      method: "GET",
    });
    const data = await response.json();
    const fileName = layer.name.replace(/\s/g, "") + Date.now() + ".csv";
    setCSV({ data: data, fileName: fileName });
    csvLink.current.link.click();
  };

  return (
               <>
                  <button
                    onClick={() => exportToCsv(layer)}
                    className="btn"
                  >
                    CSV
                  </button>
                  {csv.data && (
                    <CSVLink
                      ref={csvLink}
                      data={csv.data}
                      filename={csv.fileName}
                      target="_blank"
                    />
                  )}
            </>
  );
}

@devDroid
Copy link

Having the same issue. I don't think refs will work, since they would get overwritten by the component's own ref.

@lwoydziak
Copy link

Also experiencing this issue.

lwoydziak added a commit to lwoydziak/react-csv that referenced this issue Dec 1, 2022
This was referenced Dec 1, 2022
@riccardolardi
Copy link

Same problem here.

@lemazza
Copy link

lemazza commented Feb 23, 2023

I'm still experiencing this issue. Is there a fix?

@abdennour
Copy link
Collaborator

Hello guys, As mentioned in couple of years, the repository is open for candidates to maintain. Please apply!

@leo-arrcus
Copy link

Have done a simple workaround to handle with the async call using ref.

import React, { useEffect, useRef, useState } from "react";
import { CSVLink } from "react-csv";

export default function App() {
  const [csvLoading, setCSVLoading] = useState(false);
  const [csvData, setCSVData] = useState([]);
  const ref = useRef();

  useEffect(() => {
    if (!csvLoading || csvData.length > 0) {
      return;
    }

    // Replace this Promise with your API call
    // Then setCSVData(newData), not the dummy data.
    new Promise((r) => setTimeout(r, 2000))
      .then((newData) => {
        setCSVData([
          {
            why: "doesn't this",
            feature: "work normally???",
          }
        ]);
      })
      .catch((error) => {
        console.log(error);
      });
  }, [csvLoading]);

  useEffect(() => {
    if (csvData.length > 0 && csvLoading) {
      ref.current.link.click();
    }
  }, [csvData]);

  return (
    <div className="App">
      <button
        onClick={() => {
          if (!csvLoading && csvData.length === 0) {
            setCSVLoading(true);
          }
        }}
      >
        Download CSV
      </button>
      <CSVLink data={csvData} ref={ref} filename="data" />
    </div>
  );
}

You can find the working example here: https://codesandbox.io/s/gallant-breeze-4ym2zd?file=/src/App.js

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

9 participants