immer
是一个 JavaScript 的不可变数据(immutable data)管理库,主要用于简化对状态(state)的不可变更新操作,常见于 React、Redux 等状态管理场景。
1. 背景问题
在 React 或 Redux 中,我们通常需要保证状态 不可变(immutable),因为:
- 不可变性可以触发组件重渲染(通过浅比较
===
快速判断状态是否变化)。 - 数据修改更安全,避免意外修改共享引用,产生难以排查的 bug。
但是手动维护不可变对象很繁琐,例如:
const state = {
user: { name: "Tom", age: 20 },
hobbies: ["coding", "gaming"]
}
// 改名字时必须拷贝一层层对象
const newState = {
...state,
user: {
...state.user,
name: "Jerry"
}
}
写起来很麻烦。
2. immer
的作用
immer
通过 Proxy 代理,允许你像修改可变对象一样写代码,但最终自动生成一个不可变的新对象。
安装:
npm install immer
使用:
import { produce } from "immer"
const state = {
user: { name: "Tom", age: 20 },
hobbies: ["coding", "gaming"]
}
// 用 immer 更新状态
const newState = produce(state, (draft) => {
draft.user.name = "Jerry" // 像修改普通对象一样
draft.hobbies.push("music") // 直接改数组
})
console.log(newState)
// {
// user: { name: "Jerry", age: 20 },
// hobbies: ["coding", "gaming", "music"]
// }
特点:
state
保持原样(不可变)。newState
是新对象,只有被修改的部分是新的引用。
3. 核心 API
produce(baseState, recipe)
baseState
:原始状态recipe(draft)
:对draft
进行修改即可- 返回新的不可变对象
current(draft)
- 可以查看
draft
的当前快照(调试用)
- 可以查看
original(draft)
- 获取
draft
对应的原始对象
- 获取
4. 在 React 中的使用
在 React 的 useState
或 Redux Toolkit 中,immer
很常用:
import { useState } from "react"
import { produce } from "immer"
function App() {
const [user, setUser] = useState({ name: "Tom", age: 20 })
const changeName = () => {
setUser(
produce(user, (draft) => {
draft.name = "Jerry"
})
)
}
return (
<div>
<p>{user.name}</p>
<button onClick={changeName}>改名</button>
</div>
)
}
Redux Toolkit 内部也是用 immer
来处理 createSlice
的状态更新。
5. 总结
- immer 的本质:通过 Proxy 实现 可变写法 → 不可变数据 的自动转换。
- 优势:写法简洁、减少对象深拷贝、避免手动维护不可变性。
- 应用场景:React、Redux、状态管理、复杂数据结构更新。