不可变草稿更新(Immer)
灵感:能力工具箱 immer-draft(pkg: immer)。
用 produce 以「可变草稿」写法更新客户草稿,实际得到新对象引用,避免 Vue/React 状态被就地 mutate 导致视图不同步或撤销困难。
何时使用
- 客户草稿深层字段(联系人列表、地址嵌套)频繁改
- 需要可撤销/可对比的前后快照
- 不想手写大量展开运算
...
硬约束
- 依赖
immer;对外状态更新必须经produce(或produce封装),禁止对 store 里原对象直接赋值深层字段后当「已更新」。 produce回调内可以 push/splice;回调外把返回值赋回 state。- 与 localStorage 联用时:序列化存 produce 之后 的新对象。
- 不在
produce里发请求、不读 DOM;保持纯更新。 - TypeScript 项目保持草稿类型与客户类型一致。
推荐实现要点
import { produce } from 'immer'
export type CustomerDraft = {
id: string
name: string
mobile?: string
tags: string[]
contacts: { name: string; phone?: string }[]
}
export function patchDraft(
current: CustomerDraft,
recipe: (draft: CustomerDraft) => void,
): CustomerDraft {
return produce(current, recipe)
}
// 例:改名并追加标签
export function renameAndTag(current: CustomerDraft, name: string, tag: string) {
return patchDraft(current, (d) => {
d.name = name.trim()
if (tag && !d.tags.includes(tag)) d.tags.push(tag)
})
}
export function addContact(current: CustomerDraft, name: string, phone?: string) {
return patchDraft(current, (d) => {
d.contacts.push({ name, phone })
})
}
Agent 步骤
- 安装
immer,封装patchDraft与业务小函数。 - 所有草稿字段变更走封装;保存前可
JSON.stringify对比或写入存储。 - 自测:更新后
next !== prev,且prev.name未被改掉。
附加
- README.md · reference.md · templates/usage.md