Forming an array from two joined apis in react

Viewed 80

I am attempting to create a set of joined data from two apis that I would love to implement in a table, apparently I am not getting the expected result.

The logic behind my code is :

  1. Get the data from the first api
  2. loop through each element in the data to get a specific data from the second api depending with the id of each element.
  3. Create a new key to each element, each data obtained in second api as a value.
  4. the resulting data is set in the state.

I have been able to accomplish step 1 to 3 except step 4.

class App extends React.Component{
  constructor(props){
    super(props);
    this.state = {
      Data: [],
    };
  }


  componentDidMount() {
    fetch('http://localhost:8000/tasks?format=json')
    . then(res => res.json())
    .then(data => data['results'].forEach(element => {
      fetch(`http://localhost:8000/task/${element.id}/runs`)
      .then(res => res.json())
      .then(data2 => element['rundata'] = data2)
      .then(this.state.Data.push(element)) 
    }))
    .catch(err => console.log(err))
  }

  render(){
    console.log('data', this.state.Data)
    return(

    )
  }
}

export default App;
5 Answers

When you're setting data into the state in React you only need to use this.setState().

So for your case you only have to run this.setState({ Data: element }).

You can only update react state with setState method. Try the below code.

then(this.setState(prev => ({
    data: [...prev, element]
})

Well the main reason for the issue is that you are not using setState correctly. you need to use setState, and you need to not mutate the state. Always copy the old state and then modify it.

The second issue which may occur is that your forEach method is not synchronised. Try changing your componentDidMount to this:

componentDidMount() {
    fetch('http://localhost:8000/tasks?format=json')
        .then(res => res.json())
        .then(data => {
            for (const element of data['results']) {
                fetch(`http://localhost:8000/task/${element.id}/runs`)
                    .then(res => res.json())
                    .then(data2 => element['rundata'] = data2)
                    .then(this.setState({ Data: [...Data, element] })
            }
        }
    .catch(err => console.log(err))
  }
this.setState(prevState => ({
  myArray: [...prevState.myArray, "new value"]
}))

in the other hand, i don't recommend to loop in fetch, either you use a post method and loop throw all the ids in your server side and return an array, or if you have a light database you get all the result and do a loop in your client side.

Maybe this :

  componentDidMount() {
    fetch('http://localhost:8000/tasks?format=json')
    .then(res => res.json())
    // create array of promise
    .then(data => data.results.map(element => {
      return fetch(`http://localhost:8000/task/${element.id}/runs`)
      .then(res => element.rundata = res.json())
      .cath(err => console.log(err))
    }))
    .then((arrayPromise) => {
      Promise.all(arrayPromise)
       .then(resolved => this.setState({data:resolved}))
    })
    .catch(err => console.log(err))
  }

  render(){
    console.log('data', this.state.data)
    return(
      <></>
    )
  }
}
Related