frisk0
frisk0

Reputation: 259

Render array of objects in React

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

Answers (4)

Dyo
Dyo

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

burak
burak

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

Sujit.Warrier
Sujit.Warrier

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

izengod
izengod

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

Related Questions