1

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>
    )
  }
}
7
  • Don't set the state yet, instead use Promise.all() to run those other requests. When all requests are done, set the state. Commented Oct 18, 2018 at 1:07
  • @ChrisG if he has to use the previous result for the new request, he can't use promise.all Commented Oct 18, 2018 at 1:10
  • @GiacomoCerquone Why not...? Commented Oct 18, 2018 at 1:13
  • @ChrisG correct. I need data from the first fetch to use in the second. Basically the first response is an array of various numbers representing store numbers. The second fetch needs to run multiple times for each one of the store numbers in the array. Commented Oct 18, 2018 at 1:13
  • @ChrisG sorry I confused the question and thought that you wanted him to call promise all instead of the very first call, anyway my answer still cover the question :) Commented Oct 18, 2018 at 1:15

2 Answers 2

1

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.

Sign up to request clarification or add additional context in comments.

1 Comment

I was able to make it work using your second consideration. I used Promise.all to get everything I needed, then set the state in componentDidMount.
0

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);
  }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.