Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to async/await redux-thunk actions?

action.js

export function getLoginStatus() {
  return async(dispatch) => {
    let token = await getOAuthToken();
    let success = await verifyToken(token);
    if (success == true) {
      dispatch(loginStatus(success));
    } else {
      console.log("Success: False");
      console.log("Token mismatch");
    }
    return success;
  }
}

component.js

  componentDidMount() {
    this.props.dispatch(splashAction.getLoginStatus())
      .then((success) => {
        if (success == true) {
          Actions.counter()
        } else {
          console.log("Login not successfull");
        }
     });
   }

However, when I write component.js code with async/await like below I get this error:

Possible Unhandled Promise Rejection (id: 0): undefined is not a function (evaluating 'this.props.dispatch(splashAction.getLoginStatus())')

component.js

  async componentDidMount() {
     let success = await this.props.dispatch(splashAction.getLoginStatus());
     if (success == true) {
       Actions.counter()
     } else {
       console.log("Login not successfull");
     }
   }

How do I await a getLoginStatus() and then execute the rest of the statements? Everything works quite well when using .then(). I doubt something is missing in my async/await implementation. trying to figure that out.

like image 471
nabeel Avatar asked Jan 30 '17 06:01

nabeel


People also ask

Is redux-thunk async?

As it turns out, Redux already has an official version of that "async function middleware", called the Redux "Thunk" middleware. The thunk middleware allows us to write functions that get dispatch and getState as arguments.

How do you handle async actions in Redux?

The first solution suggested by the documentation is Redux Thunk. This middleware allows you to create Actions as more than plain objects. These new Actions can dispatch other Actions, other Thunks and also perform async operations inside them.

How do I use async await in Redux-saga?

You should never be calling the await function directly inside the saga-generator, because redux-saga is for orchestrating the side-effects. Therefore, any time that you want to run a side-effect you should do it by yielding the side-effect through a redux-saga effect (usually: call or fork ).

Is redux-thunk synchronous?

Introduction. By default, Redux's actions are dispatched synchronously, which is a problem for any non-trivial app that needs to communicate with an external API or perform side effects.


3 Answers

The Promise approach

export default function createUser(params) {   const request = axios.post('http://www...', params);    return (dispatch) => {     function onSuccess(success) {       dispatch({ type: CREATE_USER, payload: success });       return success;     }     function onError(error) {       dispatch({ type: ERROR_GENERATED, error });       return error;     }     request.then(success => onSuccess, error => onError);   }; } 

The async/await approach

export default function createUser(params) {     return async dispatch => {     function onSuccess(success) {       dispatch({ type: CREATE_USER, payload: success });       return success;     }     function onError(error) {       dispatch({ type: ERROR_GENERATED, error });       return error;     }     try {       const success = await axios.post('http://www...', params);       return onSuccess(success);     } catch (error) {       return onError(error);     }   } } 

Referenced from the Medium post explaining Redux with async/await: https://medium.com/@kkomaz/react-to-async-await-553c43f243e2

like image 94
Aspen Avatar answered Sep 20 '22 05:09

Aspen


Remixing Aspen's answer.

import axios from 'axios'

import * as types from './types'

export function fetchUsers () {
  return async dispatch => {
    try {
      const users = await axios
        .get(`https://jsonplaceholder.typicode.com/users`)
        .then(res => res.data)

      dispatch({
        type: types.FETCH_USERS,
        payload: users,
      })
    } catch (err) {
      dispatch({
        type: types.UPDATE_ERRORS,
        payload: [
          {
            code: 735,
            message: err.message,
          },
        ],
      })
    }
  }
}

 

import * as types from '../actions/types'

const initialErrorsState = []

export default (state = initialErrorsState, { type, payload }) => {
  switch (type) {
    case types.UPDATE_ERRORS:
      return payload.map(error => {
        return {
          code: error.code,
          message: error.message,
        }
      })

    default:
      return state
  }
}

This will allow you to specify an array of errors unique to an action.

like image 33
corysimmons Avatar answered Sep 21 '22 05:09

corysimmons


Another remix for async await redux/thunk. I just find this a bit more maintainable and readable when coding a Thunk (a function that wraps an expression to delay its evaluation ~ redux-thunk )

actions.js

import axios from 'axios'
export const FETCHING_DATA = 'FETCHING_DATA'
export const SET_SOME_DATA = 'SET_SOME_DATA'

export const myAction = url => {
  return dispatch => {
    dispatch({
      type: FETCHING_DATA,
      fetching: true
    })
    getSomeAsyncData(dispatch, url)
  }
}

async function getSomeAsyncData(dispatch, url) {
  try {
    const data = await axios.get(url).then(res => res.data)
    dispatch({
      type: SET_SOME_DATA,
      data: data
    })
  } catch (err) {
    dispatch({
      type: SET_SOME_DATA,
      data: null
    })
  }
  dispatch({
    type: FETCHING_DATA,
    fetching: false
  })
}

reducers.js

import { FETCHING_DATA, SET_SOME_DATA } from './actions'

export const fetching = (state = null, action) => {
  switch (action.type) {
    case FETCHING_DATA:
      return action.fetching
    default:
      return state
  }
}

export const data = (state = null, action) => {
  switch (action.type) {
    case SET_SOME_DATA:
      return action.data
    default:
      return state
  }
}
like image 45
Simon Hutchison Avatar answered Sep 19 '22 05:09

Simon Hutchison