跳至主内容区

从生产者返回新数据

[非官方测试版翻译]

本页面由 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 中使用时,若需从配方返回 nothingstate 的类型必须支持 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} 以降低认知负担。