使用 produce
egghead.io 第 3 课:使用 produce 简化深度更新
Immer 包暴露了一个完成所有工作的默认函数。
produce(currentState, recipe: (draftState) => void): nextState
produce 需要一个 baseState,以及一个可用于对传入的 draft 进行所有所需更改的 recipe。关于 Immer 的有趣之处在于 baseState 将保持不变,但 nextState 将反映对 DraftState 所做的所有更改.
在 recipe 中,所有标准的 JavaScript API 都可以在 draft 对象上使用,包括属性字段分配、删除操作和修改数组、Map 和 Set 操作,如 push、pop、splice、set、sort、remove 等。
这些 mutations 中的任何一个都不必发生在初始对象上,但它可以修改 draft 深处的任何内容:draft.todos[0].tags["urgent"].author.age = 56
请注意,recipe 函数通常不会返回任何内容。但是,如果您想用另一个对象完全替换 draft,则可以返回,有关更多详细信息,请参阅返回新数据。
例子
import {produce} from "immer"
const baseState = [
{
title: "Learn TypeScript",
done: true
},
{
title: "Try Immer",
done: false
}
]
const nextState = produce(baseState, draftState => {
draftState.push({title: "Tweet about it"})
draftState[1].done = true
})
// 新的 item 仅仅被添加到了 next state
// base state 没有被修改
expect(baseState.length).toBe(2)
expect(nextState.length).toBe(3)
// 同上
expect(baseState[1].done).toBe(false)
expect(nextState[1].done).toBe(true)
// 未修改的数据结构共享
expect(nextState[0]).toBe(baseState[0])
// 改变的数据不是
expect(nextState[1]).not.toBe(baseState[1])
术语
(base)state, 传递给produce的不可变状态recipe:produce的第二个参数,它捕获了 base state 应该如何mutated。draft: 任何recipe的第一个参数,它是可以安全mutate的原始状态的代理。producer. 一个使用produce的函数,通常形式为(baseState, ...arguments) => resultState
请注意,命名 recipe 的第一个参数 draft 并不是绝对必要的。您可以将其命名为任何您想要的名称,例如 user。使用 draft 作为名称只是一个约定,以表明:“这里的 mutation 是可以的”。