【问题标题】:Error: An immer producer returned a new value *and* modified its draft. Either return a new value *or* modify the draft错误:一个沉浸式生产者返回了一个新值*并*修改了它的草稿。返回一个新值*或*修改草稿
【发布时间】:2020-07-03 11:25:43
【问题描述】:

我有我的减速机


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

我有我的调度命令

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

/>

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

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

为什么会弹出这个错误?

【问题讨论】:

    标签: reactjs redux immer.js redux-toolkit


    【解决方案1】:

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

    根据the Immer docs on returning data,有几种方法可以解决此问题:

    • 在赋值前面添加void 运算符
    • 将赋值用花括号括起来,使其成为函数体

    所以setToken reducer 可以更新为void as

    setToken: (state, action) => void(state.token = action.payload.test)
    

    【讨论】:

      【解决方案2】:

      正确答案

      使用代替

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

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

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

      【讨论】:

        【解决方案3】:

        了解IMMER的要点

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

        现在来回答这个问题。 这是你的减速器功能

        (state, action) => state.token = action.payload.test
        

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

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

        在这种特定情况下,意图只是修改状态,所以我们必须用void撤消现有的返回

        setToken: (state, action) => void(state.token = action.payload.test)
        

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

        setToken: (state, action) => { state.token = action.payload.test } 
        

        【讨论】:

          【解决方案4】:

          代替

           state.token = action.payload.token
          

          使用

           const token = action.payload.token
           state.token = token
          

          常量是不可变的,将 action.payload 内容分配给常量为我解决了一个问题(请注意,如果有效负载是一个对象,则没有必要

          createSlice 的工作示例:

          import { createSlice } from '@reduxjs/toolkit';
          
          export const slice = createSlice({
            name: 'login',
            initialState: {
                username: "Foo",
                password: "AAA",
                authorized : false
            },
            reducers: {
              setUsername: (state, action) => {
          
                const value = action.payload
                state.username = value // action.payload.username
          
              },
              setPassword: (state, action) => {
          
                const value = action.payload
                state.password = value // action.payload.password
          
              },
              logon: (state, action) => {
          
                state.username = action.payload.username
                state.password = action.payload.password
                state.authorized = true
          
              },
              logoff: state => state.authorized = false
            },
          });
          

          【讨论】:

            【解决方案5】:

            您收到此错误,因为您正在改变状态,这是不应该的。一种解决方法是创建新状态而不参考旧状态,例如:var newState = JSON.parse(JSON.stringify(state)); 然后newState.token = action.payload.test return newState

            Copying Without Reference

            【讨论】:

              【解决方案6】:

              你可能会忘记休息;在你的 reducer.js 文件中声明;

               case LOGIN_USER_ERROR_RESET:
                      draft.errormsg = '';
                      draft.loading = false;
                      draft.error = false;
                      break;
              

              【讨论】:

                猜你喜欢
                • 2021-07-17
                • 2021-09-06
                • 2020-11-21
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2020-09-05
                • 2019-07-11
                • 2017-06-17
                相关资源
                最近更新 更多