41

I would like to know how to fetch multiple GET URLs at once and then put the fetched JSON data into my React DOM element.

Here is my code:

fetch("http://localhost:3000/items/get")
.then(function(response){
        response.json().then(
            function(data){
                ReactDOM.render(
                    <Test items={data}/>,
                    document.getElementById('overview')
                );}
        );
    })
.catch(function(err){console.log(err);});

However, I would like to fetch additional JSON datas from my server and then render my ReactDOM with all these JSON datas passed into it. For example:

ReactDOM.render(
   <Test items={data} contactlist={data2} itemgroup={data3}/>,
   document.getElementById('overview')
);

Is this possible? If not, what are other solutions to fetching multiple JSON data into my rendering ReactDOM element?

rdarioduarte
  • 1,929
  • 2
  • 21
  • 29
Jaypizzle
  • 477
  • 1
  • 5
  • 7
  • Possible duplicate of [Wait until all ES6 promises complete, even rejected promises](https://stackoverflow.com/questions/31424561/wait-until-all-es6-promises-complete-even-rejected-promises) – Dekel Sep 15 '17 at 14:23

5 Answers5

86

You can rely on Promises to execute them all before your then resolution. If you are used to jQuery, you can use jQuery Promises as well.

With Promise.all you will enforce that every request is completed before continue with your code execution

Promise.all([
  fetch("http://localhost:3000/items/get"),
  fetch("http://localhost:3000/contactlist/get"),
  fetch("http://localhost:3000/itemgroup/get")
]).then(([items, contactlist, itemgroup]) => {
    ReactDOM.render(
        <Test items={items} contactlist={contactlist} itemgroup={itemgroup} />,
        document.getElementById('overview');
    );
}).catch((err) => {
    console.log(err);
});

But even tough, fetch is not implemented in all browsers as of today, so I strongly recommend you to create an additional layer to handle the requests, there you can call the fetch or use a fallback otherwise, let's say XmlHttpRequest or jQuery ajax.

Besides of that, I strongly recommend you to take a look to Redux to handle the data flow on the React Containers. Will be more complicated to setup but will pay off in the future.

Update August 2018 with async/await

As of today, fetch is now implemented in all the latest version of the major browsers, with the exception of IE11, a wrapper could still be useful unless you use a polyfill for it.

Then, taking advantage of newer and now more stable javascript features like destructuring and async/await, you might be able to use a similar solution to the same problem (see the code below).

I believe that even though at first sight may seem a little more code, is actually a cleaner approach. Hope it helps.

try {
  let [items, contactlist, itemgroup] = await Promise.all([
    fetch("http://localhost:3000/items/get"),
    fetch("http://localhost:3000/contactlist/get"),
    fetch("http://localhost:3000/itemgroup/get")
  ]);

  ReactDOM.render(
    <Test items={items} contactlist={contactlist} itemgroup={itemgroup} />,
      document.getElementById('overview');
  );
}
catch(err) {
  console.log(err);
};
rdarioduarte
  • 1,929
  • 2
  • 21
  • 29
  • 1
    FYI fetch polyfills are easy to integrate to support browsers who have not implemented it natively yet: https://www.npmjs.com/package/whatwg-fetch – Lance Whatley Sep 15 '17 at 15:57
  • 1
    Do you also have to do .then(data => data.json) on each of the fetches? – Embedded_Mugs Feb 17 '22 at 14:16
  • @Embedded_Mugs I hope I understand your question correctly but no, you do not have to. You get the data in each one of the variables "items", "contactlist" and "itemgroup", the point of both of my proposals is to not have to do .then(...) on each one of the requests. Regardless of using async/await or not – rdarioduarte Jan 11 '23 at 16:47
24

I needed the json format response so I added a little bit of code myself

Promise.all([
            fetch(url1).then(value => value.json()),
            fetch(url2).then(value => value.json())
            ])
            .then((value) => {
               console.log(value)
              //json response
            })
            .catch((err) => {
                console.log(err);
            });
H.Sdq
  • 797
  • 3
  • 12
  • 22
15

Use some implementation of Promise.all (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all) to make multiple requests at a time, then do what you want with your data afterwards:

Promise.all([
  fetch("http://localhost:3000/items/get1"),
  fetch("http://localhost:3000/items/get2"),
  fetch("http://localhost:3000/items/get3")
]).then(allResponses => {
  const response1 = allResponses[0]
  const response2 = allResponses[1]
  const response3 = allResponses[2]

  ...

})
Lance Whatley
  • 2,395
  • 1
  • 13
  • 16
11

Here is how i fetched multiple endpoints as an example which may help someone

 const findAnyName = async() => {
const urls = ['https://randomuser.me/api/', 'https://randomuser.me/api/'];
  try{
    let res = await Promise.all(urls.map(e => fetch(e)))
    let resJson = await Promise.all(res.map(e => e.json()))
    resJson = resJson.map(e => e.results[0].name.first)
    console.log(resJson)
  }catch(err) {
    console.log(err)
  }
}
findAnyName()

Here is a complete example you can check on JSFiddle

Or try this: declare all your URLs as an array. we will loop through this array and refer to single URL as array index.

     constructor(props) {
        super(props);
        this.state = { World: [], Afghanistan: [], USA: [], Australia: [] };
    }                                                                           
                       
 const urls = [
            'https://corona.lmao.ninja/v2/all',
            'https://corona.lmao.ninja/v2/countries/afghanistan',
            'https://corona.lmao.ninja/v2/countries/usa',
            'https://corona.lmao.ninja/v2/countries/australia'
        ];
    
    Promise.all(urls.map(url =>
                fetch(url)
                    .then(checkStatus)  // check the response of our APIs
                    .then(parseJSON)    // parse it to Json
                    .catch(error => console.log('There was a problem!', error))
            ))
                .then(data => {
                    // assign to requested URL as define in array with array index.
                    const data_world = data[0];
                    const data_af = data[1];
                    const data_usa = data[2];
                    const data_aus = data[3];
                    this.setState({
                                World: data_world,
                                Afghanistan: data_af,
                                USA: data_usa,
                                Australia: data_aus
                            })
                })
   function checkStatus(response) {
            if (response.ok) {
                return Promise.resolve(response);
            } else {
                return Promise.reject(new Error(response.statusText));
            }
        }

    function parseJSON(response) {
        return response.json();
    }

Result

const { World, Afghanistan, USA, Australia} = this.state;

        console.log(World, Afghanistan, USA, Australia)
Amir Danish
  • 418
  • 5
  • 8
3

You can do something like this, first .then right after fetch for both requests and then get the results in an array in the main .then

    Promise.all([
      fetch(
        "https://example.com/reviews/",
        requestOptionsDoc
      ).then((res1) => res1.json()),
      fetch(
        "https://example.com/reviews/",
        requestOptionsRel
      ).then((res2) => res2.json()),
    ])
      .then(([result1, result2]) => {
        if (result1.detail) {
          setDoctorReviewDetails("No review found.");
        } else {
          setDoctorReviewDetails(result1.data.comment);
        }
        if (result2.detail) {
          setRelativeReview("No review found.");
        } else {
          setRelativeReview(result2.data.comment);
        }
      })
      .catch((error) => console.log("error", error));

Wahas Ali Mughal
  • 187
  • 2
  • 11