Reputation: 259
I have a method in a React component which fetches some data from an API
this.state.matches returns an empty array at first
loadMatches() {
let matches = this.state.matches;
forEach(this.state.matchIds.splice(0,5), matchid => {
axios.get(url)
.then(function (response) {
matches.push(response.data)
})
});
this.setState({
matches
})
}
And then a method which should map the data to React components
renderMatch() {
return this.state.matches.map((match, index) => {
return (
<Match
key={index}
gameId={match.gameId}
/>
);
});
}
renderMatch() is called in my render method with {this.renderMatch()}
But nothing is getting rendered and if i call .length it just returns 0 even though i can see in devtools that the array contains 5 objects.
Hardcoded objects in the array gets rendered
Upvotes: 0
Views: 89
Reputation: 4464
You are mutating the state so React doesn't trigger a new render. You should create a new array instead of pushing in the state :
loadMatches() {
let promises = [];
forEach(this.state.matchIds.splice(0,5), matchid => {
promises.push(axios.get(url).then(res => res.data));
});
Promise.all(promises).then(matches => {
this.setState({
matches
});
});
}
Edited to handle the async.
Upvotes: 4
Reputation: 4064
You have two main problems:
First:
.then(function (response) {
matches.push(response.data)
})
You should not change state directly, you should perform immutable update.
Second:
this.setState({
matches
})
You are updating state with empty 'matches', at this point your api call's responses are not received yet.
So, your implementation should look like this:
loadMatches() {
let matches = this.state.matches;
forEach(this.state.matchIds.splice(0,5), matchid => {
axios.get(url)
.then(function (response) {
const newMatch = response.data;
this.setState({ matches: [...matches, newMatch]});
matches.push(response.data)
})
});
}
Here some sources that you can also benefit from reading them:
https://daveceddia.com/immutable-updates-react-redux/
https://reactjs.org/docs/state-and-lifecycle.html
Upvotes: 0
Reputation: 2869
axios or fetch is an async function, there for when you call this.setState
matches is still an empty array, hence nothing is rendered. try this instead. also you are trying to mutate the state directly which is a big mistake.
loadMatches() {
let matches = this.state.matches;
let newMatches =[];
let requests = forEach(this.state.matchIds.splice(0,5), matchid => {
return new Promise((resolve) => {
axios.get(url)
.then(function (response) {
newMatches.push(response.data)
})
});
});
Promise.all(requests).then(() => {
this.setState({
matches:newMatches
})
});
}
Upvotes: 0
Reputation: 1156
axios.get
is an asynchronous function which returns a promise
. Its like you've ordered a pizza and trying to eat it before it gets delivered. You need to perform the setState()
when you resolve the promise.
axios.get(url)
.then(function (response) {
this.setState({matches: [...matches, ...response.data]})
}
Upvotes: -1