TechEmperor95 TechEmperor95 - 1 month ago 13
Javascript Question

React component method returns empty array

For a project I'm working on I wrote two react methods for requesting and parsing data from a REST API. However, the array that's supposed to hold the parsed data always returns empty. I'm not sure why this keeps happening. Any help is appreciated.

React Methods for fetching and parsing data:

getData(){
const { url, queries } = this.state;
let data_arr = [];

for (let q = 0; q < queries.length; ++q){
let query = queries[q],
post_query = {
full_name: query.name,
date_start: query.startdate,
date_end: query.enddate
};

axios.post(url, post_query).then((response) => data_arr.push(response.data));
}

return this.setState({data: data_arr});
}
parseData(){
const { data } = this.state;
let dataParsed = [];

for (let d = 0; d < data.length; ++d){
const provider_entries = data[d];
let provider_table = {
name: provider_entries[0].full_name,
size: 6,
table: {
rows: [],
columns: [
{key: 'Date', type: 'date', filterable: true, sortable: true},
{key: 'Charges', type:'number', filterable:true, sortable: true},
{key: 'Payments', type: 'number', filterable: true, sortable: true},
{key: 'Appointments'}
]
}
};

for (let p = 0; p < provider_entries.length; ++p){
const provider_row = provider_entries[p],
id_val = p++;
let row = {
id: id_val,
Date: provider_row.date,
Medical: provider_row.charges.medical,
Cosmetic: provider_row.charges.cosmetic,
Total: provider_row.charges.total,
Payments: provider_row.payments,
Appointments: provider_row.appointments
};

provider_table.table.rows.push(row);
}

dataParsed.push(provider_table);
}

return this.setState({ data_formatted: dataParsed });

}
componentDidMount(){
this.datafetch = setInterval(() => {
this.getData();
this.parseData();

const { data, data_formatted } = this.state;

console.log(data, data_formatted);
}, 5000);
}


example of data from Rest API:

[
[
{
first_name: "First Name Here...",
last_name: "Last Name Here...",
full_name: "Full Name Here",
date: "2016-01-17",
charges: {
cosmetic: 25000.00,
medical: 25000.00,
total: 50000.00
},
payments: 75000.00,
appointments: 99,
pk: 5
},
{
first_name: "First Name Here...",
last_name: "Last Name Here...",
full_name: "Full Name Here",
date: "2016-01-24",
charges: {
cosmetic: 25000.00,
medical: 25000.00,
total: 50000.00
},
payments: 75000.00,
appointments: 99,
pk: 5
},
],
[
{
first_name: "First Name Here...",
last_name: "Last Name Here...",
full_name: "Full Name Here",
date: "2016-01-17",
charges: {
cosmetic: 25000.00,
medical: 25000.00,
total: 50000.00
},
payments: 75000.00,
appointments: 99,
pk: 5
},
{
first_name: "First Name Here...",
last_name: "Last Name Here...",
full_name: "Full Name Here",
date: "2016-01-24",
charges: {
cosmetic: 25000.00,
medical: 25000.00,
total: 50000.00
},
payments: 75000,
appointments: 99,
pk: 5
},
]
];

Answer

The problem you have is that you are making ajax calls which are Async and setting state right after. The workflow is: You make the api calls with the axios, chain that to a .then function that will execute after the data comes back, it will then push that data into your array. The actual javascript workflow is like this: You make the ajax calls, instead of waiting for responses to come back javascript continues executing and runs your setstate function. At the time it runs the setState function your data array is still empty because no responses have come back.

If it were me I would look into using axios.all which takes an array of ajax calls to make and you can chain a .then function to that and it will be ran once all api calls are done. at that point you can push all the data into the data array and setState within that same .then block. This will ensure that the state gets updated once the data has actually come back.

if you check this article http://codeheaven.io/how-to-use-axios-as-your-http-client/#performing-multiple-requests-simultaneously it explains how to do multiple api calls at once

something like the following should work, i didn't have chance to test so i'd double check it but it should do what i am talking about

getData(){
    const { url, queries } = this.state;
    let data_arr = [];

    // map over queries, create array of axios promises
    const axiosQueries = queries.map(function(query) {
      let post_query = {
          full_name: query.name,
          date_start: query.startdate,
          date_end: query.enddate
      };
      return axios.post(url, post_query)
    });
  // set self to be equal to react component 
  var self = this; 
  // chain all axios promises and then give the results back as an array containing each request
   axios.all(axiosQueries).then(function(results){

   // go through each result and push it into data array
     results.forEach(function(response) {
       data_arr.push(response.data)
     })

     // once all data is processed set state to data array.
     return self.setState({data: data_arr});

   })

}
Comments