从生产者返回新数据
本页面由 PageTurner AI 翻译(测试版)。未经项目官方认可。 发现错误? 报告问题 →
egghead.io lesson 9: Returning completely new state
无需从生产者返回任何内容,因为 Immer 始终会返回 draft 的(最终)版本。但直接 return draft 也是允许的。
允许从生产者函数返回任意其他数据,但前提是你没有修改草稿。这可用于生成全新状态。例如:
const userReducer = produce((draft, action) => {
switch (action.type) {
case "renameUser":
// OK: we modify the current state
draft.users[action.payload.id].name = action.payload.name
return draft // same as just 'return'
case "loadUsers":
// OK: we return an entirely new state
return action.payload
case "adduser-1":
// NOT OK: This doesn't do change the draft nor return a new state!
// It doesn't modify the draft (it just redeclares it)
// In fact, this just doesn't do anything at all
draft = {users: [...draft.users, action.payload]}
return
case "adduser-2":
// NOT OK: modifying draft *and* returning a new state
draft.userCount += 1
return {users: [...draft.users, action.payload]}
case "adduser-3":
// OK: returning a new state. But, unnecessary complex and expensive
return {
userCount: draft.userCount + 1,
users: [...draft.users, action.payload]
}
case "adduser-4":
// OK: the immer way
draft.userCount += 1
draft.users.push(action.payload)
return
}
})
注意:无法通过此方式返回 undefined,因为它与未更新草稿的情况无法区分!继续阅读...
使用 nothing 生成 undefined
通常可以通过生产者中直接 return 新值来替换当前状态,而无需修改草稿。但存在一个微妙边界情况:当尝试用 undefined 替换当前状态时:
produce({}, draft => {
// don't do anything
})
对比:
produce({}, draft => {
// Try to return undefined from the producer
return undefined
})
问题在于 JavaScript 中未返回值的函数同样会返回 undefined!因此 Immer 无法区分这两种情况。默认情况下,Immer 会假定任何返回 undefined 的生产者都是在尝试修改草稿。
若需明确告知 Immer 你确实要生成 undefined,可返回内置标记 nothing:
import {produce, nothing} from "immer"
const state = {
hello: "world"
}
produce(state, draft => {})
produce(state, draft => undefined)
// Both return the original state: { hello: "world"}
produce(state, draft => nothing)
// Produces a new state, 'undefined'
注意:此问题仅针对 undefined 值,其他值(包括 null)不受影响。
提示:在 TypeScript 中使用时,若需从配方返回 nothing,state 的类型必须支持 undefined 值。
使用 void 的内联快捷方式
egghead.io lesson 10: Avoid accidental returns by using _void_
Immer 中的草稿修改通常需要代码块,因为返回(return)意味着覆盖。这有时会使代码略显冗长。
此时可使用 JavaScript 的 void 运算符,它会执行表达式并返回 undefined。
// Single mutation
produce(draft => void (draft.user.age += 1))
// Multiple mutations
produce(draft => void ((draft.user.age += 1), (draft.user.height = 186)))
代码风格因人而异,但对于多人协作的代码库,我们建议坚持使用经典写法 draft => { draft.user.age += 1} 以降低认知负担。