Bruno Crosier
Bruno Crosier

Reputation: 758

Multiple Fetch requests to set state in React

I would like to map over an array to make multiple fetch requests, and update the state based on the results of those fetch requests.

I can achieve this with Promise.all() but it means that I have to wait for all the fetch requests to resolve - I would like to update the state on an "as and when" basis so that the UI can be updated sooner.

This is some pseudo-code to explain what I'm trying to do:

const [masterState, setMasterState] = useState(null);

useEffect(() => {
  const fetchData = async (name) => {
    const initialData = await fetch(`http://example.com/api/${name}`);
    const jsonResponse = await initialData.json()
    setMasterState(jsonResponse)
  };

  ["Bill", "Bob", "Brian"].map(name => fetchData(name));

}, [thingThatChanged]);

Does anyone have any advice? Is this even possible ?

Upvotes: 3

Views: 1916

Answers (2)

Rashomon
Rashomon

Reputation: 6762

Its possible. You should make sure the data is merged correctly in the useEffect:

// Init the data as an empty array
const [masterState, setMasterState] = useState([]);

useEffect(() => {
  const fetchData = async (name) => {
    const initialData = await fetch(`http://example.com/api/${name}`);
    const jsonResponse = await initialData.json()
    // To avoid sync problems, use the previous value of the state, 
    // instead of getting it from masterState (its not garantized to be updated). 
    // Use spread operator to merge the new value in the array cleanly
    setMasterState(previousState => [...previousState, jsonResponse])
  };
  // forEach is more appropiate since you are not creating a new array. 
  // You are just executing something for each element
  ["Bill", "Bob", "Brian"].forEach(name => fetchData(name));

}, [thingThatChanged]);

Upvotes: 5

Sohail Ashraf
Sohail Ashraf

Reputation: 10569

You could use the for loop to loop over the array and call the fetch method.

With this the code will execute sequentially, means it will wait for the the first promise to be fulfilled and then will call the second promise.

And you could use the callback in setState method.

const [masterState, setMasterState] = useState(null);

useEffect(() => {
  const fetchData = async (name) => {
    const initialData = await fetch(`http://example.com/api/${name}`);
    const jsonResponse = await initialData.json()
    setMasterState( prevState => [...masterState, ...jsonResponse]);
  };
  let inputArray = ["Bill", "Bob", "Brian"];
  (async function() {
    for(const item of inputArray) {
        fetchData(name)
      }
  })();


}, [thingThatChanged]);

Upvotes: 1

Related Questions