Reputation: 276
I am in the process of learning React and making HTTP requests.
Recently Im trying to implement a dropdown for the webpage that Im working on. In my code I had to loop through an array of id, and make a post request for each of the id to extract the metadata. So Im encountering a problem with the dropdown options. The dropdown options are suppose to be the names for the corresponding id.
The array of id is an array of objects that looks like this
[{key: "someidnumber1", count: 5}, {key: "someidnumber2", count: 5}, {key: "someidnumber3", count: 10},....]
So what I did first is to loop through the id array, and make a post request on each of the id as parameter. This is inside my render method.
render() {
return(
<SomeOtherComponent>
{ //Do something to fetch the ids
let promises = [];
let names = [];
let options = [];
ids.map(id => {
promises.push(
axios
.post(TARGET_META_URL, {
filters: [
{
field: "id",
values: [id.key]
}
]
})
.then(response => {
// adding the name from the data into the names array
names.push(response.data[0].name);
})
});
Promise.all(promises).then(() => {
// Wait for the promises to collection all the names
// and pass into a new array
options = [...names];
}
return (
<Dropdown
options={options}
/>
);
}
</SomeOtherComponent>
);
}
My dropdown options after opening it is empty. So I did a couple console log and figured out that the options is declared outside the Promise.all so when the render() method is called, the dropdown takes in an empty array. I need help on how to setup the options for the dropdown so it waits for all the code before it finish running. I tried putting the second return inside the Promise.all() but I get an error method saying that render() doesn't have a return.
Upvotes: 1
Views: 161
Reputation: 898
Maybe this will help -
componentDidMount() {
let promises = [];
let options = [];
ids.map(id => {
promises.push(
axios
.post(TARGET_META_URL, {
filters: [
{
field: "id",
values: [id.key]
}
]
})
});
Promise.all(promises).then((response) => {
// Wait for the promises to collection all the names
// and pass into a new array
options = response.map(res => res.data[0].name);
this.setState({ options })
}
}
render() {
return(
<SomeOtherComponent>
{ this.state.options?.length ? <Dropdown options={this.state.options} /> : null }
</SomeOtherComponent>
);
}
Upvotes: 1
Reputation: 370679
Make another component which fetches the data and renders them once the responses have come back. Use Promise.all
to wait for all of the Promises to resolve together.
const getName = id => axios
.post(TARGET_META_URL, {
filters: [
{
field: "id",
values: [id.key]
}
]
})
.then(response => response.data[0].name);
const AsyncDropdown = ({ ids }) => {
const [options, setOptions] = useState();
useEffect(() => {
Promise.all(ids.map(getName))
.then(setOptions)
.catch((err) => {
// handle errors
});
}, [ids]);
return options ? <Dropdown options={options} /> : null;
}
And replace your original render method with:
render() {
return(
<SomeOtherComponent>
<AsyncDropdown ids={ids} />
</SomeOtherComponent>
);
}
Upvotes: 2