how to setstate after saga async request
I was stuck with the same problem...
My solution was wrapping the dispatch in a promise and call the resolve and reject in a saga function...
I created a hook to wrap the dispatch. You can see my example here: https://github.com/ricardocanelas/redux-saga-promise-example
I hope that can help somebody.
Every api call you make is processed as an async request but handled using a generator function in a saga.
So, After a successful api call, you can do the following possible things.
- Make another api call like
function* onLogin(action) { try { const { userName, password } = action; const response = yield call(LoginService.login, userName, password); yield put(LoginService.loginSuccess(response.user.id)); const branchDetails = yield call(ProfileService.fetchBranchDetails, response.user.user_type_id); yield put(ProfileActions.fetchBranchDetailsSuccess(branchDetails)); } catch (error) { yield put(ProfileActions.fetchUserDetailsError(error)); } }
Pass a Callback after successfull api
onLoginClick() { const { userName, password } = this.state; this.props.login(userName, password, this.onLoginSuccess); } onLoginSuccess(userDetails) { this.setState({ userDetails }); } function *onLogin(action) { try { const { userName, password, onLoginSuccess } = action; const response = yield call(LoginService.login, userName, password); if (onLoginSuccess) { onLoginSuccess(response); } yield put(LoginService.loginSuccess(response.user.id)); const branchDetails = yield call(ProfileService.fetchBranchDetails, response.user.user_type_id); yield put(ProfileActions.fetchBranchDetailsSuccess(branchDetails)); } catch (error) { yield put(ProfileActions.fetchUserDetailsError(error)); }
}
Update Reducer State and get from props by mapStateToProps
yield put(LoginService.loginSuccess(response.user.id)); @connect( state => ({ usedDetails: state.user.get('usedDetails'), }) ) static getDerivedStateFromProps(nextProps, prevState) { const { usedDetails } = nextProps; return { usedDetails } }
But i can't do this with saga, because saga doesn't return promise
Redux-saga
is slightly different from thunk
since it is process manager, not simple middleware: thunk
performs reaction only on fired actions, but saga
has its own "process" (Formally callback tick domain) and can manipulate with actions by effects.
Usual way to perform async actions with redux-saga
is splitting original actions to ACTION_REQUEST
, ACTION_SUCCESS
and ACTION_FAILURE
variants. Then reducer accepts only SUCCESS/FAILURE actions, and maybe REQUEST for optimistic updates.
In that case, your saga
process can be like following
function* actionNameSaga(action) {
try {
const info = yield call(fetch, { params: action.params }
yield put('ACTION_NAME_SUCCESS', info)
} catch(err) {
yield put('ACTION_NAME_FAILURE', err)
}
function* rootSaga() {
yield takeEvery('ACTION_NAME', actionNameSaga)
}
Keep in mind that yield
operation itself is not about promise waiting - it just delegates async waiting to saga process manager.