Stangn99
Stangn99

Reputation: 117

Use fetch results to make another fetch request (JS/React)

What's the best approach to using the results of one fetch request to make another fetch request to a different endpoint? How can I confirm the first fetch has completed and setState has happened?

class ProductAvailability extends React.Component {
  state = {
    store_ids: []
  }
  componentDidMount() {
    fetch(`myapi.com/availability?productid=12345`)
    .then((results) => {
      return results.json();
    })
    .then((data) => {      
      const store_ids = data.result.map((store) => {
        return store.store_id
      })
      this.setState({store_ids: store_ids})
    })

    /* At this point I would like to make another request
       to myapi.com/storedata endpoint to obtain information 
       on each store in the state.store_ids, and add details 
       to the state */
  }


  render() {
    return (
      <div>
        <p>STORE INFO FROM STATE GOES HERE</p>
      </div>
    )
  }
}

Upvotes: 1

Views: 1164

Answers (2)

Matt Carlotta
Matt Carlotta

Reputation: 19772

Easier to do with async/await (.then/.catch requires a bit more work -- also, reference to Bluebird's Promise.each function). For clarity, its best to move this out of componentDidMount and into its own class method.

As a side note, if this action is happening for every product, then this secondary query should be handled on the backend. That way, you only need to make one AJAX request and retrieve everything you need in one response.

componentDidMount = () => this.fetchData();


fetchData = async () => {
  try {
    const productRes = fetch(`myapi.com/availability?productid=12345`) // get product data
    const productData = await productRes.json(); // convert productRes to JSON

    const storeIDs = productData.map(({store_id}) => (store_id)); // map over productData JSON for "store_ids" and store them into storeIDs

    const storeData = [];
    await Promise.each(storeIDs, async id => { // loop over "store_ids" inside storeIDs
      try {
        const storeRes = await fetch(`myapi.com/store?id=${id}`); // fetch data by "id"
        const storeJSON = await storeRes.json(); // convert storeRes to JSON
        storeData.push(storeJSON); // push storeJSON into the storeData array, then loop back to the top until all ids have been fetched
      } catch(err) { console.error(err) }
    });

    this.setState({ productData, storeData }) // set both results to state
  } catch (err) {
    console.error(err);
  }
}

Upvotes: 0

Giacomo Cerquone
Giacomo Cerquone

Reputation: 2478

When you do setState, it updates the component, so the natural point to read state after you've done a setstate, if you'd have read the docs, is in componentDidUpdate(prevProps, prevState). I leave you to the doc: https://reactjs.org/docs/react-component.html#componentdidupdate Attention: Don't use willupdate, it's unsafe as you read in the docs.

A further consideration could be done. If you could avoid to put these data in the state, you could also do everything in the componendDidMount (with promiseall for all the other requests maybe) and then set the state with the old and new data, this is preferable since you update your component only once.

Upvotes: 1

Related Questions