简体   繁体   English

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

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

I'm trying to import typescript in my redux application.我正在尝试在我的 redux 应用程序中导入 typescript。 I use redux toolkit createSlice function like this:我像这样使用 redux 工具包 createSlice function:

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

When I dispatch a updateMode action, I receive the following error:当我调度 updateMode 操作时,我收到以下错误:

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

But my action.payload is well defined and redux toolkit is up to date.但是我的 action.payload 定义明确,并且 redux 工具包是最新的。 It have something to do with my code but I can't figure it out...它与我的代码有关,但我无法弄清楚......

I tried to return state in updateMode and it works, but I get a TypeScript error:我尝试在 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"'

Can someone explain to me what am I doing wrong?有人可以向我解释我做错了什么吗?

Below my full code:在我的完整代码下方:

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;

I'm a Redux maintainer and the creator of Redux Toolkit.我是 Redux 维护者和 Redux 工具包的创建者。

The actual problem is with this line:实际问题出在这一行:

state = action.payload.mode;

This doesn't actually accomplish anything useful.这实际上并没有完成任何有用的事情。 Immer works by tracking mutations to an existing value, like state.someField = 123 . Immer 通过跟踪现有值的突变来工作,例如state.someField = 123 The line you wrote only changes the local state variable to point to something else instead.您编写的行仅将本地state变量更改为指向其他内容。

Immer requires that you either return an entirely new state value, or mutate the existing state. Immer 要求您要么返回一个全新的 state 值,要么改变现有的 state。 That line of code does neither.那行代码也没有。 Instead, the reducer only ends up returning undefined , thus the error.相反,reducer 最终只返回undefined ,因此返回错误。

If you want to replace the existing state entirely, you should just do return action.payload.mode .如果你想完全替换现有的 state,你应该只做return action.payload.mode

Also, as a side note: if initialState is correctly typed, you don't have to supply a type for state for each reducer, as it will be inferred.另外,作为旁注:如果initialState输入正确,则不必为每个减速器提供state的类型,因为它会被推断出来。

Following the document, you might have to cast your type as following:在文档之后,您可能必须将您的类型转换如下:

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

Typically you would have something like this通常你会有这样的东西

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;

And then wherever you are importing this slice and you have to dispacth your action you will then have something like.然后无论你在哪里导入这个切片,你必须分发你的动作,你就会得到类似的东西。

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

....

// somewhere in your component/view or whatever

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

Essentially your slice holds a slice of your global state stored by redux and you are slicing down and manipulating just a slice of it.本质上,您的切片包含由 redux 存储的全局 state 的切片,您正在切片并仅操作它的切片。 The slice contains both the reducer(s) and the action(s) that allow you to manipulate your state(slice of the state).切片包含减速器和允许您操纵状态(状态切片)的操作。

React Boilerplate CRA has some good explanations about it right here . React Boilerplate CRA在这里有一些很好的解释。

Thanks everyone for your answers.谢谢大家的回答。

I merged both your answers and I get the following result wich does what I wanted:我合并了你的两个答案,我得到了以下结果,这正是我想要的:

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;

This allows me to have my mode slice in my global state equal "SHOW_LIST" ||这使我可以在我的全局 state 中使用我的模式切片等于“SHOW_LIST”|| "SHOW_SKILL" which is what I wanted in the first place. “SHOW_SKILL”,这是我一开始想要的。 If I need more data for my mode, I will surely make my slice state like this:如果我的模式需要更多数据,我肯定会让我的切片 state 像这样:

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

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

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