Using async and await with React and Redux

in react

I've been playing around with using async and await in my Redux reducers to get rid of all the Promise callback functions - this stuff's like magic!

Note: I'm using Webpack and compiling with the babel-preset-stage-0 for ES2016 await/async.

Before

This is my login function using a Promise and fetch to send data to the API:

export const login = (username, password) => {
  // using thunk middleware since it's async, so return a function
  return (dispatch) => {
    // create data to send via fetch
    const data = new FormData();
    data.append("username", username);
    data.append("password", password);

    // fire the request
    fetch("http://localhost/login", {
      method: "POST",
      body: data,
    })
      // wait for data back
      .then((response) => response.json())

      // response.json() is also async, so wait for that to finish
      .then((data) => dispatch(loginSuccess(data)))

      // catch any errors
      .catch((err) => dispatch(loginFailure(err)));
  };
};

After

Here's the function now I'm using async/await: I've split it into two functions so the async login request isn't nested. There's also no callback then() functions!

// this just wraps fetch - a simpler 'GET' could just be inline
// note the 'async' keyword
async function loginRequest(username, password) {
  const data = new FormData();
  data.append("username", username);
  data.append("password", password);

  // 'await' the response from fetch - no callback, you can just carry on
  // and use 'response' as normal rather than wrap it in a function!
  const response = await fetch("http://localhost/login", {
    method: "POST",
    body: data,
  });

  // response.json() is async too, but you don't need an 'await'
  // keyword in a return from 'async' (it's implied)
  return response.json();
}

// this is the reducer - no 'async' on the outer function since it just returns a function
export const login = (username, password) => {
  // this one's 'async'
  return async (dispatch) => {
    // wrap in try to listen for Promise rejections - equivalent of '.catch()'
    try {
      // wait for the fetch to finish then dispatch the result
      const data = await loginRequest(username, password);
      dispatch(loginSuccess(data));
    } catch (e) {
      // catch errors from fetch
      dispatch(loginFailure(e));
    }
  };
};