如何正确使用redux工具包的preloadedState和createSlice?

jwk*_*koo 9 redux redux-toolkit

我正在尝试迁移到 redux 工具包,但遇到了一个问题。

这是一个简单计数器切片的示例。

import { createSlice } from "@reduxjs/toolkit";

const initialState = {
  value: 0,
};

export const counterSlice = createSlice({
  name: "counter",
  initialState,
  reducers: {
    increment: (state) => {
      state.value += 1;
    },
    decrement: (state) => {
      state.value -= 1;
    },
  },
});

export const { increment, decrement } = counterSlice.actions;
export default counterSlice.reducer;

Run Code Online (Sandbox Code Playgroud)

这是一个使用configureStore 创建的商店。

import { configureStore } from "@reduxjs/toolkit";
import counterReducer from "./slice";

export const store = configureStore({
  reducer: {
    counter: counterReducer,
    // later, many other reducers will be added here.
  },
});

Run Code Online (Sandbox Code Playgroud)

还是有什么问题啊

但是如果我引入preloadedState,就存在问题。

const store = configureStore({
    reducer: counterReducer,
    preloadedState: {
      counter: {
         value: 10
      }
    },
  });
Run Code Online (Sandbox Code Playgroud)

如果我像下面这样记录商店的状态,它将按预期记录。

   // without using preloadedState, it results to {counter: {value: 0}}
   console.log(store.getState())
   // with using preloadedState, it results to {counter: {value: 10}}
   console.log(store.getState())
Run Code Online (Sandbox Code Playgroud)

但是使用切片减速器时会出现问题,因为切片减速器使用自己的状态。

   ...
     reducers: {
       increment: (state) => {
         state.value += 1;  // not work anymore if using preloadedState. we have to use state.counter.value instead.
       },
       decrement: (state) => {
         state.value -= 1;  // not work anymore if using preloadedState. we have to use state.counter.value instead.
       },
     },
   ...
Run Code Online (Sandbox Code Playgroud)

相反我们必须使用,

   ...
     reducers: {
       increment: (state) => {
         state.counter.value += 1; 
       },
       decrement: (state) => {
         state.counter.value -= 1;
       },
     },
   ...
Run Code Online (Sandbox Code Playgroud)

所以问题是,我们是否必须添加条件语句,根据我们是否使用 preloadedState 来分离切片减速器内部的逻辑?

每当提供 preloadedState 时,如果切片减速器使用 preloadedState 而不是使用它自己的状态,那就太好了。还有更好的方法吗?

谢谢。

phr*_*hry 6

如果您查看 Redux Devtools 浏览器扩展,您会注意到 - 由于您只有一个减速器并且您将其作为根减速器传递,因此您的状态具有以下形状:

{
  value: 10
},
Run Code Online (Sandbox Code Playgroud)

此时您的正常状态只是没有计数器减速器的子项,因为您的整个状态就是计数器减速器。

如果你希望你的状态有一个合理的结构(并且将来能够使用多个reducer),你必须将键添加reducer为一个对象:

const store = configureStore({
    reducer: {
      counter: counterReducer,
    },
    preloadedState: {
      counter: {
         value: 10
      }
    },
  });
Run Code Online (Sandbox Code Playgroud)

正如您在开发工具中注意到的那样,现在您的状态结构就是您所期望的 - 并且预加载的状态也将与之匹配。

但请记住,从现在开始,在选择器中您将必须useSelector(state => state.counter.value)