繁体   English   中英

Redux + Typescript -> 错误:不可草拟值上的大小写缩减器不得返回未定义的 redux

[英]Redux + Typescript -> Error: A case reducer on a non-draftable value must not return undefined redux

我正在尝试在我的 redux 应用程序中导入 typescript。 我像这样使用 redux 工具包 createSlice function:

const slice = createSlice({
  name: sliceName,
  initialState,
  reducers: {
    updateMode(state: SliceState, action: PayloadAction<ModePayload>) {
      state = action.payload.mode;
    },
  },
});

当我调度 updateMode 操作时,我收到以下错误:

Error: A case reducer on a non-draftable value must not return undefined

但是我的 action.payload 定义明确,并且 redux 工具包是最新的。 它与我的代码有关,但我无法弄清楚......

我尝试在 updateMode 中返回 state 并且它可以工作,但我收到 TypeScript 错误:

Type '(state: SliceState, action: { payload: ModePayload; type: string; }) => SliceState' is not assignable to type 'CaseReducer<"SHOW_LIST", { payload: any; type: string; }> | CaseReducerWithPrepare<"SHOW_LIST", PayloadAction<any, string, any, any>>'.
  Type '(state: SliceState, action: { payload: ModePayload; type: string; }) => SliceState' is not assignable to type 'CaseReducer<"SHOW_LIST", { payload: any; type: string; }>'.
    Type 'SliceState' is not assignable to type 'void | "SHOW_LIST"'.
      Type '"SHOW_SKILL"' is not assignable to type 'void | "SHOW_LIST"'

有人可以向我解释我做错了什么吗?

在我的完整代码下方:

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

type SliceState = "SHOW_LIST" | "SHOW_SKILL";

let initialState: SliceState = "SHOW_LIST";

const sliceName = "mode";

interface ModePayload {
  mode: SliceState;
}

//--- Slice reducer ---

const modeSlice = createSlice({
  name: sliceName,
  initialState,
  reducers: {
    updateMode(state: SliceState, action: PayloadAction<ModePayload>) {
      return (state = action.payload.mode);
    },
  },
});
export const { updateMode } = modeSlice.actions;
export default modeSlice.reducer;

我是 Redux 维护者和 Redux 工具包的创建者。

实际问题出在这一行:

state = action.payload.mode;

这实际上并没有完成任何有用的事情。 Immer 通过跟踪现有值的突变来工作,例如state.someField = 123 您编写的行仅将本地state变量更改为指向其他内容。

Immer 要求您要么返回一个全新的 state 值,要么改变现有的 state。 那行代码也没有。 相反,reducer 最终只返回undefined ,因此返回错误。

如果你想完全替换现有的 state,你应该只做return action.payload.mode

另外,作为旁注:如果initialState输入正确,则不必为每个减速器提供state的类型,因为它会被推断出来。

在文档之后,您可能必须将您的类型转换如下:

const modeSlice = createSlice({
  name: sliceName,
  initialState: initialState as SliceState,
  reducers: {
    updateMode(state: SliceState, action: PayloadAction<ModePayload>) {
      return (state = action.payload.mode);
    },
  },
});

通常你会有这样的东西

type SliceState = {
  mode: string;
};

interface ModePayload {
  mode: string;
}

const initialState: SliceState = {
  mode: 'initial mode',
};

//--- Slice reducer ---

const modeSlice = createSlice({
  name: 'modeSlice',
  initialState,
  reducers: {
    updateMode(state, action: PayloadAction<ModePayload>) {
      state.mode = action.payload.mode;
    },
  },
});

export const { actions, reducer, name: sliceKey } = modeSlice;

然后无论你在哪里导入这个切片,你必须分发你的动作,你就会得到类似的东西。

import {actions} from '../mode-slice'

....

// somewhere in your component/view or whatever

dispatch(actions.updateMode({mode: 'new mode'}))

本质上,您的切片包含由 redux 存储的全局 state 的切片,您正在切片并仅操作它的切片。 切片包含减速器和允许您操纵状态(状态切片)的操作。

React Boilerplate CRA在这里有一些很好的解释。

谢谢大家的回答。

我合并了你的两个答案,我得到了以下结果,这正是我想要的:

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

type SliceState = "SHOW_LIST" | "SHOW_SKILL";

let initialState: SliceState = "SHOW_LIST";

const sliceName = "mode";

interface ModePayload {
  mode: SliceState;
}

//--- Slice reducer ---

const modeSlice = createSlice({
  name: sliceName,
  initialState: initialState as SliceState,
  reducers: {
    updateMode(state, action: PayloadAction<ModePayload>) {
      return action.payload.mode;
    },
  },
});
export const { updateMode } = modeSlice.actions;
export default modeSlice.reducer;

这使我可以在我的全局 state 中使用我的模式切片等于“SHOW_LIST”|| “SHOW_SKILL”,这是我一开始想要的。 如果我的模式需要更多数据,我肯定会让我的切片 state 像这样:

{
  mode: "SHOW_LIST",
  otherAttribute: otherValue,
  ...,
}

暂无
暂无

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

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