Reputation: 12874
Basically I have a screen that calls multiple APIs at componentDidMount
, and each and every API will fire a network request along with a callback, something as below
componentDidMount() {
new APIManager.fetchBooks(this.handleBooks);
new APIManager.fetchAuthor(this.handleAuthor);
new APIManager.fetchShops(this.handleShops);
}
...
handleBooks = (result) => {
this.setState({ books: result });
}
...
And basically all the fetch
methods works pretty similarly, it accepts a single parameter which is a callback from the component, pseudocode as below
export async function fetchBooks(callback) {
const result = await callNetworkAPI();
callback(result);
}
This was working fine on both Android and iOS at react-native v0.53 but it's not working anymore at v0.59.10 on iOS.
What's happening now is that, fetchBooks
, fetchAuthor
and fetchShops
will all still be triggered but this.handleBooks
, this.handleAuthor
will no longer be triggered. It's like they lost their cursor.
I've made it work such that all API calls has to be using await
, something as below
async componentDidMount() {
const books = await APIManager.fetchBooks();
const authors = await APIManager.fetchAuthor();
const shops = await APIManager.fetchShops();
this.handleBooks(books);
this.handleAuthors(authors);
this.handleShops(shops);
}
And of course updates to my APIManager
as below:
export async function fetchBooks() {
const result = await callNetworkAPI();
return result;
}
Its working fine, but all 3 API calls cannot be asynchronously anymore because I made it await for the previous API call before proceeding. I'm wondering if there's a better way to handle my problem? Or I'm totally on the right track?
Upvotes: 21
Views: 91409
Reputation: 402
Hope so It will help you for multiple API calls simultaneously.
React.useEffect(()=>{
Promise.all([
fetch('https://jsonplaceholder.typicode.com/posts'),
fetch('https://jsonplaceholder.typicode.com/users')
]).then(function (responses) {
// Get a JSON object from each of the responses
return Promise.all(responses.map(function (response) {
return response.json();
}));
}).then(function (data) {
// Log the data to the console
// You would do something with both sets of data here
console.log(data);
}).catch(function (error) {
// if there's an error, log it
console.log(error);
});
},[])
Upvotes: 9
Reputation: 10700
You could use Promise.all
to wait for multiple requests in parallel:
async componentDidMount() {
const [books, authors, shops] = await Promise.all([
APIManager.fetchBooks(),
APIManager.fetchAuthor(),
APIManager.fetchShops(),
]);
this.handleBooks(books);
this.handleAuthors(authors);
this.handleShops(shops);
}
This however waits for all 3 requests to be completed before calling handleBooks
/ handleAuthors
/ handleShops
.
If you want them to call their handle method directly after they completed, you could use .then()
on the individual fetch calls:
async componentDidMount() {
await Promise.all([
APIManager.fetchBooks().then(this.handleBooks),
APIManager.fetchAuthor().then(this.handleAuthors),
APIManager.fetchShops().then(this.handleShops),
]);
// All fetch calls are done now
console.log(this.state);
}
(this works because async
functions always return a promise)
About your problem with the fetch calls, you might be affected by this react-native
bug:
Multiple fetch request starts to not resolve or reject promise
According to the github issue page, it should be fixed in version 1.2.1
of react-native
.
Upvotes: 36