跳至主内容区

Immer 简介

[非官方测试版翻译]

本页面由 PageTurner AI 翻译(测试版)。未经项目官方认可。 发现错误? 报告问题 →

Immer

Immer(德语意为"总是")是一个小巧的包,让您能够以更便捷的方式处理不可变状态。

Immer 彻底改变了 JavaScript 开发者的工作方式,我一点都没夸张 :) 它简直和 Prettier 一样,属于那种"哇这个库太棒了,我以前没它时是怎么活过来的?"级别的神器。——Mark Erikson(Redux 维护者),@replayio

2019年荣获 React 开源奖 "年度突破"和 JavaScript 开源奖 "最具影响力贡献"。



Immer 简化不可变数据结构处理

Immer 适用于任何需要不可变数据结构的场景,例如结合 React 状态、React 或 Redux 的 reducer,或配置管理。不可变数据结构支持(高效)变更检测:如果对象引用未改变,则对象本身未改变。此外,它使克隆操作相对廉价:数据树中未更改的部分无需复制,可与旧版本状态共享内存。

通常这些优势要求开发者绝不直接修改对象、数组或映射的属性,而是始终创建修改后的副本。但在实践中,这会导致代码冗长繁琐,且容易意外违反约束。Immer 通过解决以下痛点帮助您遵循不可变数据范式:

  1. Immer 会检测意外变更并抛出错误

  2. Immer 消除了深度更新不可变对象所需的样板代码:无 Immer 时,每层都需要手动创建对象副本(通常使用大量 ... 展开操作符)。使用 Immer 时,所有变更都在 draft 对象上进行,该对象记录变更并负责创建必要副本,绝不影响原始对象

  3. 使用 Immer 无需学习专用 API 或数据结构:您将继续使用原生 JavaScript 数据结构和熟悉的可变 API,但以安全的方式操作

简单示例对比

const baseState = [
{
title: "Learn TypeScript",
done: true
},
{
title: "Try Immer",
done: false
}
]

假设我们有基础状态,需要更新第二个待办事项并添加第三个。但我们既不想改变原始 baseState,又想避免深度克隆(以保留第一个待办事项)。

不使用 Immer

没有 Immer 时,必须小心地对状态结构中受变更影响的每一层进行浅拷贝:

const nextState = baseState.slice() // shallow clone the array
nextState[1] = {
// replace element 1...
...nextState[1], // with a shallow clone of element 1
done: true // ...combined with the desired update
}
// since nextState was freshly cloned, using push is safe here,
// but doing the same thing at any arbitrary time in the future would
// violate the immutability principles and introduce a bug!
nextState.push({title: "Tweet about it"})

使用 Immer

使用 Immer 过程将更加直观。我们可以利用 produce 函数:第一个参数传入初始状态,第二个参数传入一个称为 配方 的函数,该函数会接收到可进行直接变更的 draft 草稿对象。这些变更将被记录,并在配方函数执行完毕后用于生成新状态。produce 将自动处理所有必要的拷贝操作,并通过冻结数据防止未来的意外修改。

import {produce} from "immer"

const nextState = produce(baseState, draft => {
draft[1].done = true
draft.push({title: "Tweet about it"})
})

寻找 React 结合 Immer 的用法?可直接跳转至 React + Immer 页面。

Immer 工作原理

核心思想是通过 Immer 将所有变更应用在临时 草稿(即 currentState 的代理对象)上。当所有变更完成后,Immer 会根据草稿状态的改动生成 nextState。这意味着您只需直接修改数据即可,同时保留不可变数据的所有优势。

immer-hd.png

使用 Immer 如同拥有个人助理:助理取来信件(当前状态)并给您副本(草稿)进行修改。完成后,助理将根据草稿生成真正的不可变终稿(下一状态)。

前往 下一章节 深入了解 produce

核心优势

  • 遵循不可变数据范式,同时使用标准 JavaScript 对象/数组/Set/Map,无需学习新 API 或 "变更模式"!

  • 强类型支持,无需基于字符串的路径选择器

  • 开箱即用的结构共享

  • 开箱即用的对象冻结

  • 轻松实现深层更新

  • 减少样板代码,更简洁的实现

  • 原生支持 JSON Patch

  • 轻量:压缩后仅 3KB