Let's say I have a saga that looks so:
export function* incrementAsync(action) {
try {
const res = yield call(Api.signin.create, action.payload);
yield put({
type: USER_SIGN_IN_FETCH_SUCCESS,
payload: res.data.auth
};
} catch (e) {
yield put({ type: USER_SIGN_IN_FETCH_ERROR_NETWORK });
}
}
The fech was a success, but that doesn't mean that the user was actually logged in:
res.data.auth.error
could be true
My question is whether I should do things like:
if (//user was succesfully logged in)
yield put(//user was successfully logged in)
else if //wrong username
yield put(//wrong username)
else if //wrong password
yield put(//wrong password)
Or should I have only one for success and one for error, and in the reducer analyze the logic and build the store relative to the response data?
As of 2020, we specifically recommend putting as much logic as possible in reducers: Wherever possible, try to put as much of the logic for calculating a new state into the appropriate reducer, rather than in the code that prepares and dispatches the action (like a click handler).
1. Logic inside the Component. You also import the action into this component file and map the action to props as well.
So, the more logic you can put in a reducer, the more logic you have that is easily testable. This is a silly one, but is often prone to mistakes. We know that as reducers are pure functions, we should not mutate the state directly inside them, instead create and return a new state object.
At its core, Redux is only a state container that supports synchronous data flows: every time an action is sent to the store, a reducer is called and the state is updated immediately. But in an asynchronous flow, you have to wait for the response first; then, if there's no error, you can update the state.
Error logic should always be handled at sagas
.
In this particular case your API is not throwing a correct error because if your API call was not a success
(200
, for example), that logic should be handled at your catch statement.
Why is this error not being handled there?
If you are using axios
, this could happen as a consequence of a bad design of the API (i.e. returning 200 instead of 400 for an error in signin in).
If it's just you doing it by hand you should throw an error and handle that logic at catch
in sagas
.
So my recommendation is:
catch
statement.If you have to parse the response in order to programmatically throw the error do it at the API layer if you can.
Make a specific action to handle the signup error OR just make a generic FAIL action and pass an error message to it(an then store it at redux to show it).
It should look something like:
export function* incrementAsync(action) {
try {
const res = yield call(Api.signin.create, action.payload);
yield put({
type: USER_SIGN_IN_FETCH_SUCCESS,
payload: res.data.auth
};
} catch (error) {
yield put({ type: USER_SIGN_IN_FAIL, payload: error.message });
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With