Home > Blockchain >  Trying to export data to csv file from my firebase data gives undefined
Trying to export data to csv file from my firebase data gives undefined

Time:11-09

I have a list of data from my firebase firestore that I want to export to .csv

I did everything that is required but when I add the values that I want to be exported they are always undefined.

I am not an expert in react I am somewhat intermediate but I think it is because I am setting my data inside a useEffect Hook.

My data useState is undefined, although it holds values and I can see them in my table, which is causing the CSVLink to throw errors.

How do I allow my data to be passed into the headers?

Here is my code:

  const [data, setData] = useState([]);
  const [id, setID] = useState("");
  const list = []
  const filteredList = []
  useEffect(() => {
    firebase.firestore().collection("Users").get().then((userSnapshot) => {

      userSnapshot.forEach((doc) => {
       
        const {powerAccount,first_name,registerDate,email,company,country,phone} = doc.data();
        setID(doc.data().usersID)
        list.push({
          usersID:doc.id,
          powerAccount:powerAccount,
          first_name:first_name,
          registerDate:registerDate,
          email:email,
          company:company,
          country:country,
          phone:phone,
        });
      });
      setData(list);
    });
  },[]);


const headers = [
                  // here all the keys give undefined.
    {label:'User',key:data.usersID},
    {label:'Account',key:data.powerAccount},
    {label:'Name',key:data.first_name},
    {label:'RegistrationDate',key:data.registerDate},
    {label:'Email',key:data.email},
    {label:'Company',key:data.company},
    {label:'Country',key:data.country},
    {label:'Phone',key:data.phone},
  ];

 const csvReport = {
    filename:"userReport.csv",
    headers:headers,
    data: data // also my data useState is undefined, although it holds values and i can see them in my table
  }

    return (
     <CSVLink  {...csvReport} >
            Export
     </CSVLink>
    )

CodePudding user response:

You should all state coordination / update to useState and useEffect hooks and avoid relying on any field update outside the scope of these.

You should then remove the list variable, move state update to your effect hook and consolidate all users data in the same structure:

const [data, setData] = useState([]);
useEffect(() => {
  firebase.firestore()
    .collection("Users")
    .get()
    .then((userSnapshot) => {
      const usersData = [];
      userSnapshot.forEach((doc) => {
        const { powerAccount, first_name, registerDate, email, company, country, phone, userID } = doc.data();
        const userData = {
          usersID: doc.id,
          powerAccount: powerAccount,
          first_name: first_name,
          registerDate: registerDate,
          email: email,
          company: company,
          country: country,
          phone: phone,
        };
        const headers = [
          // here all the keys give undefined.
          { label: 'User', key: userID },
          { label: 'Account', key: powerAccount },
          { label: 'Name', key: first_name },
          { label: 'RegistrationDate', key: registerDate },
          { label: 'Email', key: email },
          { label: 'Company', key: company },
          { label: 'Country', key: country },
          { label: 'Phone', key: phone },
        ];
        const csvReport = {
          filename: "userReport.csv",
          headers: headers,
          data: userData
        }
        usersData.push(csvReport);
      });
      setData(usersData);
    });
}, []);

return (
  <CSVLink  {...data} >
    Export
  </CSVLink>
)

You may need add loading state to reflect the UI effect of data being loaded.

CodePudding user response:

According to your implementation, fetching data from firebase is async so the csvData is getting undefined because it's not updating after a state update Try changing your code like this and let me know if it works fine

const [data, setData] = useState({
  filename: "userReport.csv",
  headers: [],
  data: [],
});
const [id, setID] = useState("");
const filteredList = [];
useEffect(() => {
  firebase
    .firestore()
    .collection("Users")
    .get()
    .then((userSnapshot) => {
      let list = [];
      userSnapshot.forEach((doc) => {
        const {
          powerAccount,
          first_name,
          registerDate,
          email,
          company,
          country,
          phone,
        } = doc.data();
        setID(doc.data().usersID);
        list.push({
          usersID: doc.id,
          powerAccount: powerAccount,
          first_name: first_name,
          registerDate: registerDate,
          email: email,
          company: company,
          country: country,
          phone: phone,
        });
      });
      const headers = [
        // I'm not sure why you need this key
        // but if it's only for uniqueness
        // you can replace them by unique strings like
        // { label: "User", key: "user" },
        // { label: "Account", key: "account" },

        { label: "User", key: data.usersID },
        { label: "Account", key: data.powerAccount },
        { label: "Name", key: data.first_name },
        { label: "RegistrationDate", key: data.registerDate },
        { label: "Email", key: data.email },
        { label: "Company", key: data.company },
        { label: "Country", key: data.country },
        { label: "Phone", key: data.phone },
      ];

      const csvReport = {
        filename: "userReport.csv",
        headers: headers,
        data: list,
      };
      setData(csvReport);
    });
}, []);

return <CSVLink {...data}>Export</CSVLink>;

CodePudding user response:

I think there are two things that causes the problem that you need to understand.

  1. Asynchronous Function
  2. React Lifecycle

Fetching data from firebase is asynchronous and might take sometime before you get the returned data while you have saved csvReport as constant variables and set it up as React element properties. So when firebase is still loading your data and your react component is already rendered / mounted, your data state has value of [] from default value as defined in the useState statement. Based on your code, your csvReport constant variable will not be receiving new data from firebase unless your app is re-rendered (enter new lifecycle and repeat). For example, switching to other tab component and go back to this component without refreshing the browser.

const csvReport = {
    filename:"userReport.csv",
    headers:headers, => [{ label: "User", key: undefined }, ...etc]; undefined bcs `data` is []
    data: data => the value is []
  }

So the simple solution is NOT to save the data as constant variable and set up the React element properties directly from your useState variable. Based on your code, I would make some changes like this.

...your previous code

const getHeaders = () => {
  // Do your data manipulation using `data` in useState
  // For example:
  const headers = data && data.map(item => {return {id: item.id}})
  return headers
}

return (
  <CSVLink
    filename="userReport.csv"
    headers={getHeaders()}
    data={data}
  >
     Export
  </CSVLink>
)

Hope this helps and have fun making changes :)

  • Related