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

sua*_*kim 6 reactjs redux redux-thunk redux-reducers redux-toolkit

我对整个 React 和 Redux 生态系统相当陌生,我试图了解在使用 Redux 工具包时何时以及为何使用额外的减速器,而不是直接在异步 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 };
    }))
    // ...
  },
});

// ...
Run Code Online (Sandbox Code Playgroud)

版本 2:在 async 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,
    }),
    // ...
  },
});

// ...
Run Code Online (Sandbox Code Playgroud)

问题

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

  • 两个版本基本上都可以/正确还是我遗漏了一些东西?
  • 坚持“extraReducers方法”有什么好处吗?
    这个特定示例中的一个小缺点是我必须loginResponseToUserInfo在两个位置(异步 thunk 和 )执行转换extraReducer,而我只需要在第二个版本中调用它一次......

Ji *_*aSH 5

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

为了证明我的选择是正确的:

  • 您应该将“操作”视为“事件”,事件是“用户登录成功”。将数据设置到切片中的显式操作是一种错误的模式
  • 将每个切片视为应该能够独立工作的子模块。负责身份验证的模块不应该关心其他切片是否正在监听其事件;将来您可能会对此事件感兴趣,并且您不希望在 thunk 中出现几个无关的调度 + '登录成功' 事件可能会从另一个源触发。