Error: An immer producer returned a new value *and* modified its draft. Either return a new value *or* modify the draft
Error: An immer producer returned a new value *and* modified its draft. Either return a new value *or* modify the draft
我有我的减速器
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"}))}
/>
当我按下按钮时,我得到的是这个错误:
我已经隔离了所有内容以确保这是问题所在,而不是其他问题。
为什么会弹出这个错误?
问题是使用没有花括号的箭头函数作为缩减器,因为它充当隐式 return 语句。所以,你们都在改变 state.token
、 和 return 赋值的结果。
根据 the Immer docs on returning data,有几种方法可以解决此问题:
- 在赋值前添加
void
运算符
- 将赋值包裹在大括号中使其成为函数体
所以 setToken
reducer 可以更新为 void
as
setToken: (state, action) => void(state.token = action.payload.test)
而不是
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
},
});
你可能会忘记休息;在您的 reducer.js 文件中声明;
case LOGIN_USER_ERROR_RESET:
draft.errormsg = '';
draft.loading = false;
draft.error = false;
break;
要了解的要点IMMER
- 如果您 return 除了从配方函数中起草任何其他内容,该 return 值将替换状态
- 你主要想改变草稿来改变状态,**所以 return修改草稿后是可选的**,
immer
无论如何都会 return 最终确定草稿
- 如果您 return 来自
recipe
函数的任何其他内容,那么根据第 1 点,新的 return 值将替换状态
- 第3点是可以的,前提是你的recipe函数中没有修改草稿。即你可以选择两者之一
一个。修改草案 --> return draft 或 undefined,两者都可以
b。想要 return 一些新值,那么根本不要碰草稿
现在来回答问题。
这是你的减速器功能
(state, action) => state.token = action.payload.test
这个函数做两件事,
1。修改状态
2。 returning action.payload.test
所以它违反了第 4 点,因此来自 Immer 库的错误
在这种特定情况下,目的只是修改状态,所以我们必须用 void
撤消现有的 return
setToken: (state, action) => void(state.token = action.payload.test)
但是,Immer 库建议使用代码块来确保跨大型代码库的一致性,此代码块隐式 return未定义
setToken: (state, action) => { state.token = action.payload.test }
尝试为 Copying Without Reference
检查此 link
正确答案
Use Instead of
const userAuthSlice = createSlice({
name: "userAuth",
initialState: {
token: '',
},
reducers: {
setToken: (state, action) => state.token = action.payload.test,
},
});
Use this {I have just added brackets}
const userAuthSlice = createSlice({
name: "userAuth",
initialState: {
token: '',
},
reducers: {
setToken: (state, action) => { state.token = action.payload.test}, // <<= Change Here
},
});
对于那些使用 React PullState 的人,我的问题是语法:
我有:
const onUpdate = (value: any) => {
someStore.update((s) => (s.value = value));
};
但必须是:
const onUpdate = (value: any) => {
someStore.update((s) => {
s.value = value;
});
};
出于某种原因,不喜欢第一种方法中声明的箭头函数。
我有我的减速器
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"}))}
/>
当我按下按钮时,我得到的是这个错误:
我已经隔离了所有内容以确保这是问题所在,而不是其他问题。
为什么会弹出这个错误?
问题是使用没有花括号的箭头函数作为缩减器,因为它充当隐式 return 语句。所以,你们都在改变 state.token
、 和 return 赋值的结果。
根据 the Immer docs on returning data,有几种方法可以解决此问题:
- 在赋值前添加
void
运算符 - 将赋值包裹在大括号中使其成为函数体
所以 setToken
reducer 可以更新为 void
as
setToken: (state, action) => void(state.token = action.payload.test)
而不是
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
},
});
你可能会忘记休息;在您的 reducer.js 文件中声明;
case LOGIN_USER_ERROR_RESET:
draft.errormsg = '';
draft.loading = false;
draft.error = false;
break;
要了解的要点IMMER
- 如果您 return 除了从配方函数中起草任何其他内容,该 return 值将替换状态
- 你主要想改变草稿来改变状态,**所以 return修改草稿后是可选的**,
immer
无论如何都会 return 最终确定草稿 - 如果您 return 来自
recipe
函数的任何其他内容,那么根据第 1 点,新的 return 值将替换状态 - 第3点是可以的,前提是你的recipe函数中没有修改草稿。即你可以选择两者之一
一个。修改草案 --> return draft 或 undefined,两者都可以
b。想要 return 一些新值,那么根本不要碰草稿
现在来回答问题。 这是你的减速器功能
(state, action) => state.token = action.payload.test
这个函数做两件事,
1。修改状态
2。 returning action.payload.test
所以它违反了第 4 点,因此来自 Immer 库的错误
在这种特定情况下,目的只是修改状态,所以我们必须用 void
setToken: (state, action) => void(state.token = action.payload.test)
但是,Immer 库建议使用代码块来确保跨大型代码库的一致性,此代码块隐式 return未定义
setToken: (state, action) => { state.token = action.payload.test }
尝试为 Copying Without Reference
检查此 link正确答案
Use Instead of
const userAuthSlice = createSlice({
name: "userAuth",
initialState: {
token: '',
},
reducers: {
setToken: (state, action) => state.token = action.payload.test,
},
});
Use this {I have just added brackets}
const userAuthSlice = createSlice({
name: "userAuth",
initialState: {
token: '',
},
reducers: {
setToken: (state, action) => { state.token = action.payload.test}, // <<= Change Here
},
});
对于那些使用 React PullState 的人,我的问题是语法:
我有:
const onUpdate = (value: any) => {
someStore.update((s) => (s.value = value));
};
但必须是:
const onUpdate = (value: any) => {
someStore.update((s) => {
s.value = value;
});
};
出于某种原因,不喜欢第一种方法中声明的箭头函数。