Where should the response logic happen, in the saga or the reducer?

问题: 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({...

问题:

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?


回答1:

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:

  • Throw an error to the sagas to handle error logic at 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 });
  }
}

回答2:

I'd always move as much logic as possible to the reducer. Logic there is more visible in the dev tools, if you do it in the saga it can be harder. It is also easier to test, as it's a synchronous and pure function. Also, USER_SIGN_IN_FETCH_SUCCESS seems perfectly meaningful to me for an action send from saga to reducer (actions from components to reducer should be less technical).

  • 发表于 2019-03-10 14:44
  • 阅读 ( 205 )
  • 分类:sof

条评论

请先 登录 后评论
不写代码的码农
小编

篇文章

作家榜 »

  1. 小编 文章
返回顶部
部分文章转自于网络,若有侵权请联系我们删除