使用额外的 reducer 与在异步 thunk 中调度的优缺点

Pros & cons of using extra reducers vs dispatching within async thunk

我对整个 React 和 Redux 生态系统还比较陌生,我正在尝试了解何时以及为何在使用 Redux 工具包时使用额外的 reducer 与直接在异步 thunk 中调度操作。

可能最好用一个显示两种解决方案的例子来解释:

版本 1:使用额外的减速器

auth.slice.ts

// ...

export const login = createAsyncThunk<LoginResponse, LoginData>(
  'auth/login',
  async ({ email, password }, thunkAPI) => {
    const data = await AuthService.login(email, password);

    // Extract user info from login response which holds other information as well
    // in which we're not interested in the auth slice...
    const userInfo = loginResponseToUserInfo(data);
    LocalStorageService.storeUserInfo(userInfo);

    // Return the whole login response as we're interested in the other data
    // besides the user info in other slices which handle `login.fulfilled` in
    // their own `extraReducers`
    return data;
  }
);

// ...

const authSlice = createSlice({
  // ...
  extraReducers: builder => {
    builder.addCase(login.fulfilled, (state, { payload }) => {
      // Again: Extract user info from login response which holds other
      // information as well in which we're not interested in the auth slice...
      const userInfo = loginResponseToUserInfo(payload);
      return { ...state, userInfo };
    }))
    // ...
  },
});

// ...

版本 2:在异步 thunk 中使用分派

auth.slice.ts

// ...

export const login = createAsyncThunk<LoginResponse, LoginData>(
  'auth/login',
  async ({ email, password }, thunkAPI) => {
    const data = await AuthService.login(email, password);

    // Extract user info from login response which holds other information as well
    // in which we're not interested in the auth slice...
    const userInfo = loginResponseToUserInfo(data);
    LocalStorageService.storeUserInfo(userInfo);

    // !!! Difference to version 1 !!!
    // Directly dispatch the action instead of using `extraReducer` to further
    // process the extracted user info
    thunkAPI.dispatch(authSlice.actions.setUserInfo(userInfo));

    // Return the whole login response as we're interested in the other data
    // besides the user info in other slices which handle `login.fulfilled` in
    // their own `extraReducers`
    return data;
  }
);

// ...

const authSlice = createSlice({
  // ...
  reducers: {
    setUserInfo: (state, { payload }: PayloadAction<UserInfo>) => ({
      ...state,
      userInfo: payload,
    }),
    // ...
  },
});

// ...

问题

如果我没有完全错的话,这两个例子做的事情完全一样,但是通过互联网我发现大多数人建议使用 extraReducer 的选项 1,这就是我问的原因:

在我看来两者都是有效的,尽管我个人会选择#1。

证明我的选择:

  • 你应该把'actions'当成'events',事件是'user logon successfull'。将数据设置到切片中的明确操作有点错误模式
  • 将您的每个切片视为应该能够独立工作的子模块。负责认证的模块不应该关心其他切片是否正在监听它的事件;将来您可能在此事件中有其他切片,并且您不希望在您的 thunk 中以几个无关的分派结束 + 'logon success' 事件可能会从另一个来源触发。