错误:沉浸式制作人返回了一个新值*并且*修改了其草稿。返回一个新值*或*修改草稿

Iva*_*ear 10 reactjs redux immer.js redux-toolkit

我有我的减速机


const userAuthSlice = createSlice({
    name: "userAuth",
    initialState: {
        token: '',
    },
    reducers: {
        setToken: (state, action) => state.token = action.payload.test,
    },
});

Run Code Online (Sandbox Code Playgroud)

我有我的调度命令

<button
   value={text.sign_in.submit}
   onClick={() => dispatch(userAuthSlice.actions.setToken({test:"test"}))}

/>
Run Code Online (Sandbox Code Playgroud)

当我按下按钮时,我得到的是这个错误:

在此处输入图片说明

我已经隔离了所有内容,以确保这是问题所在,而没有其他问题。

为什么会弹出这个错误?

mar*_*son 27

问题是使用没有花括号的箭头函数作为 reducer,因为它充当隐式 return 语句。所以,你们都在改变state.token返回赋值的结果。

根据有关返回数据的 Immer 文档,有几种方法可以解决此问题:

  • void在赋值前添加运算符
  • 用花括号包裹赋值,使其成为函数体

所以setToken减速器可以更新void

setToken: (state, action) => void(state.token = action.payload.test)
Run Code Online (Sandbox Code Playgroud)


Aks*_*ain 13

需要了解的要点IMMER

  1. 如果您从配方函数返回草稿以外的任何内容,则该返回值将替换状态
  2. 你主要想改变草稿来改变状态,**所以修改后返回草稿是可选的**,immer无论如何都会返回最终的草稿
  3. 如果您从函数返回任何其他recipe内容,则根据第 1 点,新的返回值将替换状态
  4. 第3点是可以的,只要你不修改你的菜谱函数中的草稿。即您可以选择两者之一
    。修改草稿 --> 返回草稿或未定义,两者都可以
    b. 想要返回一些新值,那么根本不要碰草稿

现在来回答问题。这是你的减速函数

(state, action) => state.token = action.payload.test
Run Code Online (Sandbox Code Playgroud)

这个函数做了两件事,
1.修改状态
2.返回action.payload.test

所以它违反了第4点,因此来自Immer库的错误

在这种特定情况下,目的只是修改状态,因此我们必须撤消现有返回void

setToken: (state, action) => void(state.token = action.payload.test)
Run Code Online (Sandbox Code Playgroud)

但是,Immer 库建议使用代码块来确保大型代码库的一致性,此代码块隐式返回 undefined

setToken: (state, action) => { state.token = action.payload.test } 
Run Code Online (Sandbox Code Playgroud)


小智 11

正确答案

使用代替

const userAuthSlice = createSlice({
    name: "userAuth",
    initialState: {
        token: '',
    },
    reducers: {
        setToken: (state, action) => state.token = action.payload.test,
    },
});
Run Code Online (Sandbox Code Playgroud)

使用这个{我刚刚添加了括号}

const userAuthSlice = createSlice({
    name: "userAuth",
    initialState: {
        token: '',
    },
    reducers: {
        setToken: (state, action) => { state.token = action.payload.test}, // <<= Change Here
    },
});
Run Code Online (Sandbox Code Playgroud)