如何使用 redux-toolkit 访问另一个切片的减速器中一个切片的状态

Neh*_*pta 10 javascript reactjs redux react-redux redux-toolkit

我正在尝试使用 getState() 方法访问另一个切片的减速器中另一个切片的状态,但看起来这是不允许的,因此 Web 应用程序会中断。

有谁知道访问另一个切片的减速器内一个切片的状态的推荐方法是什么?我的网络应用程序需要这个。

预先感谢您的任何帮助

Ian*_*n A 15

根据Redux 文档,您可以使用 3 种不同的方法:

许多用户后来想尝试在两个reducer之间共享数据,但发现combineReducers不允许他们这样做。可以使用以下几种方法:

  1. 如果一个reducer需要知道来自另一个状态切片的数据,则可能需要重新组织状态树形状,以便单个reducer能够处理更多的数据。
  2. 您可能需要编写一些自定义函数来处理其中一些操作。这可能需要用您自己的顶级减速器函数替换combineReducers。您还可以使用诸如reduce-reducers之类的实用程序来运行combineReducers来处理大多数操作,但也可以为跨状态切片的特定操作运行更专门的reducer。
  3. 具有异步逻辑的中间件(例如 redux-thunk)可以通过 getState() 访问整个状态。动作创建者可以从状态中检索附加数据并将其放入动作中,以便每个减速器都有足够的信息来更新自己的状态切片。

例子

假设我们有以下切片:

const namesSlice = createSlice({
  name: "Names",
  initialState: {
    value: [],
    name: "Names"
  },
  reducers: {
    ...
  }
};

const counterSlice = createSlice({
  name: "Counter",
  initialState: {
    value: 0,
    name: "Names"
  },
  reducers: {
    ...
  }
};

const reducer = combineReducers({
  counter: counterReducer,
  names: namesReducer
});
Run Code Online (Sandbox Code Playgroud)

我们想要定义一个操作addName,它将添加一个名称(由用户输入)到names数组中,但也会在添加之前将状态的当前值附加counter到名称上。

选项 1:重组切片

这涉及将 2 个切片合并为一个切片,因此最终会得到如下结果:

const namesSlice = createSlice({
  name: "NamesAndCounter",
  initialState: {
    value: {
      names: [],
      counter: 0
    },
    name: "NamesAndCounter"
  },
  ...
};
Run Code Online (Sandbox Code Playgroud)

这将允许您访问减速器中的names和。counter

如果您不想重组状态/切片,则有选项 2 和 3:

选项2:使用reduce-reducers

可以使用第三方库reduce-reducers

在这里,您将定义一个跨切片减速器,它能够访问counternames切片:

export const crossSliceReducer = (state, action) => {
  if (action.type === "CROSS_SLICE_ACTION") {
    const newName = action.payload + state.counter.value;
    const namesState = state.names;
    state = {
      ...state,
      names: { ...namesState, value: [...state.names.value, newName] }
    };
  }
  return state;
};

// Combine reducers
const reducer = combineReducers({
  counter: counterReducer,
  names: namesReducer
});

// Add the cross-slice reducer to the root reducer
const rootReducer = reduceReducers(reducer, crossSliceReducer);

// Create store
const store = configureStore({
  reducer: rootReducer
});
Run Code Online (Sandbox Code Playgroud)

然后您可以调度以下操作来调用减速器:

dispatch({ type: "CROSS_SLICE_ACTION", payload: name });
Run Code Online (Sandbox Code Playgroud)

注意:reduce-reducers不再维护

选项 3:使用 thunk

使用 thunk(适用于调用 API 等异步操作)可以让您获取整个状态。您可以定义一个引用函数的 thunk,该getState函数允许您获取全局状态中的任何切片:

export const addWithThunk = createAsyncThunk(
  "names/addWithThunk",
  async (name, { getState }) => {
    return name + getState().counter.value;
  }
);
Run Code Online (Sandbox Code Playgroud)

extraReducersthunk 在传递给 的参数的属性中定义createSlice()

extraReducers: (builder) => {
    builder.addCase(addWithThunk.fulfilled, (state, action) => {
      state.value.push(action.payload);
    });
  }
Run Code Online (Sandbox Code Playgroud)

并且可以以与调用普通操作相同的方式进行调用:

dispatch(addWithThunk(name));
Run Code Online (Sandbox Code Playgroud)

有一个CodeSandbox 演示显示选项 2 和 3。当您使用其中一个按钮添加名称时Submit,它将访问counter状态并将计数器的当前值附加到您输入的名称,然后再将名称添加到状态中names