首页 > 解决方案 > 如何在 React 应用程序中使用 redux 工具包更新不同减速器(切片)中的嵌套项

问题描述

我有以下代码(我删除了大部分代码以使其更容易理解 - 但一切正常):

“角色”减速机:

 // some async thunks      
        
   const rolesSlice = createSlice({
           name: "role",
           initialState,
           reducers: { // some reducers here  },
           extraReducers: {
             // a bunch of extraReducers
             [deleteRole.fulfilled]: (state, { payload }) => {
               state.roles = state.roles.filter((role) => role._id !== payload.id);
               state.loading = false;
               state.hasErrors = false;
             },
           },
         });
export const rolesSelector = (state) => state.roles;

export default rolesSlice.reducer;

“场景”减速器:

    // some async thunks
    
    const scenesSlice = createSlice({
      name: "scene",
      initialState,
      reducers: {},
      extraReducers: {
        [fetchScenes.fulfilled]: (state, { payload }) => {
          state.scenes = payload.map((scene) => scene);
          state.loading = false;
          state.scenesFetched = true;
        }
    }

export const scenesSelector = (state) => state.scenes;

export default scenesSlice.reducer;

一个带有按钮和 handleDelete 函数的组件:

// a react functional component

function handleDelete(role) {

 // some confirmation code

      dispatch(deleteRole(role._id));
  }

我的场景模型(和商店状态)如下所示:

   [
    {
     number: 1,
     roles: [role1, role2]
    },
    {
    number: 2,
    roles: [role3, role5]
    }
   ]

我想要实现的是,当一个角色被删除时,state.scenes 会被更新(映射场景并过滤掉每个被删除角色的出现)。

所以我的问题是,如何在不从组件调用两个不同操作的情况下更新状态(这是推荐的方式?)

提前致谢!

标签: reactjsredux-toolkit

解决方案


您可以使用 的extraReducers属性createSlice来响应在另一个切片中定义的操作,或者在切片外部定义的操作,就像它们在此处一样。

您想遍历每个场景并从角色数组中删除已删除的角色。如果您只是用最容易编写的过滤版本替换每个数组。但这会导致不必要的重新渲染,因为您要替换的某些数组未更改。相反,我们可以使用.findIndex()and .splice(),类似于这个例子

extraReducers: {
  [fetchScenes.fulfilled]: (state, { payload }) => { ... }
  [deleteRole.fulfilled]: (state, { payload }) => {
    state.scenes.forEach( scene => {
      // find the index of the deleted role id in an array of ids
      const i = scene.roles.findIndex( id => id === payload.id );
      // if the array contains the deleted role
      if ( i !== -1 ) {
        // remove one element starting from that position
        scene.roles.splice( i, 1 )
      }
    })
  }
}

推荐阅读