简体   繁体   中英

How to use redux-thunk middleware async actions with the new js async/await syntax

I'm trying to understand async actions in redux. Reading this page I got the following example:

export function fetchPosts(subreddit) {
  return (dispatch) => {
​
    dispatch(requestPosts(subreddit))
​
    return fetch(`https://www.reddit.com/r/${subreddit}.json`)
      .then(
        response => response.json(),
        // Do not use catch, because that will also catch
        // any errors in the dispatch and resulting render,
        // causing a loop of 'Unexpected batch number' errors.
        // https://github.com/facebook/react/issues/6895
        error => console.log('An error occurred.', error)
      )
      .then(json =>
        dispatch(receivePosts(subreddit, json))
      )
  }
}

About that comment, it is a common error to swallow react exceptions, what I'm trying to avoid... I'm trying to use the new javascript async/await syntax here... how the equivalent code with the exactly same behavior would be?

I thought about this first:

export function fetchPosts(subreddit) {
​
  return async (dispatch) => {

    dispatch(requestPosts(subreddit));
    try {
      const response = await fetch(`https://www.reddit.com/r/${subreddit}.json`);
      const json = await response.json();
      dispatch(receivePosts(subreddit, json));
    }
    catch (error) {
      console.log('An error occurred.', error);
    }
  }
}

But I had the feeling that this is exactly what that comment tells to avoid. Then I thought about this code:

export function fetchPosts(subreddit) {
​
  return async (dispatch) => {

    dispatch(requestPosts(subreddit));

    try {
      const response = await fetch(`https://www.reddit.com/r/${subreddit}.json`);
      const json = await response.json();
    }
    catch (error) {
      console.log('An error occurred.', error);
      return;
    }

    dispatch(receivePosts(subreddit, json));
  }
}

But in the case of an error, I'm not sure if the behavior is the same as the example without async/await. I'm not sure if I need to put that return inside the catch block. And the example returns a promise, I'm not sure if it still happens with my code.

Searching about it, I only found this question but without response, and I found a redux-saga component that uses generators/yield syntax. Should I use redux-saga instead of redux-thunk with async/await?

Yes, I believe your second example is equivalent to the promise-based snippet, although there's a syntax error.

You're catching only errors from the fetch() call itself, and in the case of an error, logging it and stopping there. Assuming there was no error, it dispatches the action. And yes, all async functions automatically return a promise.

The error is that the const json = await response.json() is block-scoped, so the json variable won't be accessible outside the try {} block. You'd want to declare let json; before the try , so that you can refer to it afterwards.

My feeling is that the original code should actually have been

export function fetchPosts(subreddit) {
  return (dispatch) => {
    dispatch(requestPosts(subreddit));
    return fetch(`https://www.reddit.com/r/${subreddit}.json`)
      .then(response =>
        response.json()
      )
      .then(json =>
        dispatch(receivePosts(subreddit, json))
      , error => {
        // Do not use catch, because that will also catch
        // any errors in the dispatch and resulting render,
        // causing a loop of 'Unexpected batch number' errors.
        // https://github.com/facebook/react/issues/6895
        console.log('An error occurred.', error)
      });
  }
}

where the error handler is the alternative to the dispatch of receivePosts(subreddit, json) , instead of the alternative to the JSON parsing (and unconditionally followed by the dispatch with a possibly undefined json value).

This kind of branching is hard to achieve with try / catch when using async / await , so I would just keep the then syntax. If you want to rewrite it, your second attempt is fine (and equivalent to my corrected then syntax), but you would need to declare json outside of the try block (or use var instead of const ):

export function fetchPosts(subreddit) {
  return async (dispatch) => {
    dispatch(requestPosts(subreddit));
    let json;
//  ^^^^^^^^
    try {
      const response = await fetch(`https://www.reddit.com/r/${subreddit}.json`);
      json = await response.json();
    } catch (error) {
      console.log('An error occurred.', error);
      return;
    }
    dispatch(receivePosts(subreddit, json));
  }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM