简体   繁体   English

如何使用 redux-toolkit 在另一个切片的 reducer 中访问一个切片的状态

[英]How to access state of one slice in reducer of another slice using redux-toolkit

I am trying to access state of another slice in reducer of another slice using getState() method but looks like this is not allowed and hence the web application breaks.我正在尝试使用 getState() 方法在另一个切片的减速器中访问另一个切片的状态,但看起来这是不允许的,因此 Web 应用程序会中断。

Does anyone know whats the recommended way to access state of a slice inside reducer of another slice?有谁知道在另一个切片的减速器中访问切片状态的推荐方法是什么? I need this for my web application.我的网络应用程序需要这个。

Thanks in advance for your any help提前感谢您的任何帮助

According to the Redux docs , there are 3 different approaches you could use:根据Redux 文档,您可以使用 3 种不同的方法:

Many users later want to try to share data between two reducers, but find that combineReducers does not allow them to do so.许多用户后来想尝试在两个 reducer 之间共享数据,但发现 combineReducers 不允许他们这样做。 There are several approaches that can be used:有几种方法可以使用:

  1. If a reducer needs to know data from another slice of state, the state tree shape may need to be reorganized so that a single reducer is handling more of the data.如果 reducer 需要知道来自另一个状态切片的数据,则可能需要重新组织状态树形状,以便单个 reducer 处理更多数据。
  2. You may need to write some custom functions for handling some of these actions.您可能需要编写一些自定义函数来处理其中一些操作。 This may require replacing combineReducers with your own top-level reducer function.这可能需要用您自己的顶级 reducer 函数替换 combineReducers。 You can also use a utility such as reduce-reducers to run combineReducers to handle most actions, but also run a more specialized reducer for specific actions that cross state slices.您还可以使用 reduce-reducers 等实用程序来运行 combineReducers 来处理大多数操作,但也可以为跨状态切片的特定操作运行更专业的 reducer。
  3. Middleware with async logic such as redux-thunk have access to the entire state through getState().具有异步逻辑的中间件(例如 redux-thunk)可以通过 getState() 访问整个状态。 An action creator can retrieve additional data from the state and put it in an action, so that each reducer has enough information to update its own state slice.动作创建者可以从状态中检索额外的数据并将其放入动作中,以便每个减速器都有足够的信息来更新自己的状态切片。

Example例子

Lets assume we have the following slices:假设我们有以下切片:

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
});

And we want to define an action addName which will add a name (entered by the user) into the names array, but will also append the current value of the counter state onto the name before adding it.我们想要定义一个操作addName ,它将一个名称(由用户输入)添加到names数组中,但也会在添加之前将counter状态的当前值附加到名称上。

Option 1: Restructure Slices选项 1:重组切片

This involves merging the 2 slices into a single slice, so you'd end up with something like:这涉及将 2 个切片合并为一个切片,因此您最终会得到如下结果:

const namesSlice = createSlice({
  name: "NamesAndCounter",
  initialState: {
    value: {
      names: [],
      counter: 0
    },
    name: "NamesAndCounter"
  },
  ...
};

which would allow you to access both names and counter in the reducer.这将允许您访问减速器中的namescounter

If you don't want to restructure your state/slices, then there are options 2 and 3:如果您不想重组您的状态/切片,则有选项 2 和 3:

Option 2: Use reduce-reducers选项 2:使用 reduce-reducers

A third party library reduce-reducers can be used可以使用第三方库reduce-reducers

Here you would define a cross slice reducer which is capable of accessing both the counter and names slices:在这里,您将定义一个能够访问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
});

Then you can dispatch the following action to invoke the reducer:然后,您可以调度以下操作来调用减速器:

dispatch({ type: "CROSS_SLICE_ACTION", payload: name });

Note: The reduce-reducers library is no longer being maintained注意: reduce-reducers不再维护

Option 3: Use Thunks选项 3:使用 Thunks

Using thunks (meant for async actions like calling an API) allows you to get at the entire state.使用 thunk(用于调用 API 等异步操作)可以让您了解整个状态。 You can define a thunk that references the getState function that allows you to get at any slice in the global state:您可以定义一个引用getState函数的 thunk,该函数允许您获取全局状态中的任何切片:

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

Thunks are defined in the extraReducers property of the argument passed to createSlice() : Thunks 在传递给createSlice()的参数的extraReducers属性中定义:

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

And can be invoked in the same way you'd invoke a plain action:并且可以以与调用普通操作相同的方式调用:

dispatch(addWithThunk(name));

There's a CodeSandbox demo showing options 2 and 3. When you add a name using one of the Submit buttons, it will access the counter state and append the current value of the counter to the name you input before adding the name into the names state.有一个显示选项 2 和 3 的CodeSandbox 演示。当您使用其中一个Submit按钮添加名称时,它将访问counter状态并将计数器的当前值附加到您输入的名称中,然后再将名称添加到names状态中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM