John Spiegel
John Spiegel

Reputation: 1903

Convert array of promises to chain in React

I've seen a number of posts covering similar chaining questions, but I'm trying to understand what I'm specifically missing.

Ultimately, I want to make an API call, then make a second based on the results of the first. To do so, of course, I need to have the results, not just a promise to get them before I make the chained call. I started from an example that does not have the chaining dependency:

export const FetchUserSync = () => {
    return Promise.all([
        fetchUsers(),
        fetchPosts()
    ]).then(([user, posts]) => {
        return { user, posts };
    });
    
    function fetchUsers()...

    function fetchPosts()...
}

When I call it, the data comes back and state values are set.

useEffect(() => {
    dataPromise.then(data => {
        setUser(data.user);
        setPosts(data.posts);
    });

Attempting to change the first code so the second call will wait for the first to complete, I get results in the function (console.log or setting debbugger shows populated objects for user and posts exist), but the useEffect's calling function shows the result to be undefined.

export const FetchUserSync = () => {
    return Promise.all([fetchUsers()])
        .then(([user]) => {
            Promise.all([user, fetchPosts()]) 
                .then(([user, posts]) => {
                    return { user, posts }
                })
        });
        
        function fetchUsers()...
    
        function fetchPosts()...
    }

Any suggestions on how to make the second idea work or should I just scrap it and go with one of the other answers?

Upvotes: 0

Views: 146

Answers (1)

Kevin Bai
Kevin Bai

Reputation: 621

In this case, you wouldn't want to use Promise.all.

Since both fetchUsers and fetchPosts both return promises already, wrapping singular calls with Promises for fetchUser and fetchPosts is an anti-pattern.

Additionally, consider using async/await since they avoid deeply nested chains of data.

Here's what you could do:

export const FetchUserSync = async () => {
  const users = await fetchUsers();
  const posts = await fetchPosts();

  function fetchUsers() { ... }
  function fetchPosts() { ... }

  return { users, posts }
}

The code will make a request for users, then once users is received, it will make another call for posts.

Consider reading more on async/await: https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Asynchronous/Async_await

Upvotes: 1

Related Questions