I am having problem in executing API calls using aysnc and await. I am using a data grid which has data , column and set of dropdown options for each column to implement column filtering(data and the dropdown options I am fetching from server).
The column config array is dependent on these options where each column is tagged with options corresponding to it. I have extracted this column filter as a separate component where I pass this options .
Fetch API calls to this server work in such a way that every time I query I get an ID, and then this ID is being passed to the next function to get the actual data.
So I query the table data first, then get the dropdown values and then set the column objects so that table gets rendered properly.
But the problem here is , with the way I have written the code it should work correcly. But when I just load the page it gives me error inside getColumnFilterValues saying "cannot read param of undefined" . With async/await the dropdown values should be available prior to setting the column data. But in my case it throws the above error.
Can someone tell what is going wrong here?
import * as React from "react";
const FETCH_ID_URL = "/fetch/id";
const FETCH_DATA_URL = "/fetch/data";
export default class Test extends React.Component {
constructor(props) {
super(props);
this.state = {
data: [], // hold table data
columns: [], // hold column config
dropDownValues: [], // hold column filter dropdown values
};
}
async componentDidMount() {
await this.fetchTableData(); // First fetching the table data
await this.fetchDropDownValues(); // fetching the dropdown values for each column
this.setColumnData(); // then setting column object which is dependent on dropdown values
}
fetchDropDownValues = async () => {
await this.fetchID(FETCH_ID_URL, payload, "dropDownValues");
};
fetchTableData = async () => {
await this.fetchID(FETCH_ID_URL ,payload, "data");
};
fetchID = async (url, body, stateObject) => {
try {
const config = {
method: 'POST',
body: JSON.stringify(data)
}
let response = await fetch( url: FETCH_ID_URL, config);
setTimeout(() => this.fetchData(response, stateObject), 2000); // Waiting for the ID to receive and then call fetchData
} catch (e) {
console.log(e);
}
};
fetchData = async(obj: any, stateObject: string) => {
try {
const config = {
method: 'POST',
body: JSON.stringify(obj.id)
}
let response = await fetch( url: FETCH_DATA_URL, config);
if (stateObject === "dropDownValues") {
this.setState({ [stateObject]: response.dropdownData});
}
else
{
this.setState({[stateObject]: response.tableData});
}
} catch (e) {
console.log(e);
}
};
getValuesFromKey = (param: string) => {
let data: any = this.state.dropDownValues[param]; //Throwing error here , giving cant read param of undefined
let result = data.map((value: any) => {
let keys = Object.keys(value);
return {
field: keys[0],
checked: false,
};
});
return result;
};
setColumnData = () => {
let columns = [
{
Header: () => (
<div>
<Child
name="firstName"
options={this.getValuesFromKey("firstName")}
/>
<span>First Name</span>
</div>
),
accessor: "firstName"
},
{
Header: () => (
<div>
<Child
name="status"
options={this.getValuesFromKey("status")}
/>
<span>Status</span>
</div>
),
accessor: "status",
}
];
this.setState({ columns });
};
render() {
let { data, columns } = this.state;
return (
<ReactTable
data={data}
columns={columns}
/>
);
}
}
The problem is in this line:
setTimeout(() => this.fetchData(response, stateObject), 2000); // Waiting for the ID to receive and then call fetchData
this.setColumnData();
should be called after the setTimeout
above has finished executing. In order to do so, you need to wrap the setTimeout
in a Promise
:
return new Promise(resolve => {
setTimeout(async () => {
await this.fetchData(response, stateObject);
resolve();
}, 2000);
});