Immer的使用

Immer 是一个用于简化 JavaScript 中不可变数据操作的库,通过直观的 API 解决复杂状态管理的痛点。其核心是 写时复制(Copy-on-Write) 和 代理对象(Proxy) 机制,允许开发者以“可变”方式修改数据,同时自动生成不可变的新状态 。

🔍 一、核心概念

  1. 不可变数据的必要性
    • 避免副作用:直接修改状态易引发不可预测的 Bug,不可变数据确保状态变更可追踪 。

    • 性能优化:结构共享(Structural Sharing)仅复制修改部分,减少内存开销 。

    • 框架兼容性:React、Redux 等依赖不可变数据对比检测变更 。

  2. Immer 的工作原理
    • 代理拦截:produce 函数创建原始数据的 Proxy 代理对象(draft)。

    • 修改记录:在 draft 上的操作被拦截并记录,原始数据不受影响。

    • 生成新状态:修改完成后,Immer 根据记录生成新的不可变对象 。

🛠️ 二、基础用法

  1. 安装与导入

npm install immer

import { produce } from ‘immer’; // 核心 API

  1. 状态更新示例

const initialState = {
user: { name: “Alice”, age: 25 },
tasks: [“Learn Immer”]
};

// 修改嵌套数据
const nextState = produce(initialState, draft => {
draft.user.age = 26; // 直接修改属性
draft.tasks.push(“Build Project”); // 数组操作
});

console.log(nextState);
// { user: { name: “Alice”, age: 26 }, tasks: [“Learn Immer”, “Build Project”] }
console.log(initialState === nextState); // false(新对象)

关键点:
• draft 是原始数据的代理,修改时自动触发写时复制 。

• 未修改的属性保持引用不变(结构共享)。

⚙️ 三、高级场景

  1. 与 React 状态管理结合

useState 优化:
const [state, setState] = useState(initialState);

const updateUser = () => {
setState(produce(draft => {
draft.user.name = “Bob”;
}));
};

useReducer 简化:
const reducer = (state, action) => produce(state, draft => {
switch (action.type) {
case “ADD_TASK”:
draft.tasks.push(action.payload);
break;
case “UPDATE_AGE”:
draft.user.age = action.payload;
break;
}
}); // 避免手动扩展运算符

  1. Redux 集成

import { createReducer } from ‘@reduxjs/toolkit’; // 内置 Immer 支持

const reducer = createReducer(initialState, {
“user/update”: (draft, action) => {
draft.user = action.payload;
}
}); // 无需手动处理不可变性

  1. 性能优化

• 批量更新:使用 rebatch 合并多次修改(减少中间状态生成)。

• 避免深层嵌套:扁平化数据结构提升性能 。

• 条件更新:仅在必要时生成新状态:
produce(state, draft => {
if (draft.count !== newCount) draft.count = newCount;
});

⚠️ 四、常见问题与解决

  1. 错误:直接修改原始状态
    // ❌ 错误
    const nextState = produce(state, draft => {
    state.user.age = 30; // 直接修改原状态
    });

    // ✅ 正确:仅通过 draft 修改
    draft.user.age = 30;

  2. 调试技巧
    • 启用 enablePatches 追踪变更:
    import { produce, enablePatches } from ‘immer’;
    enablePatches(true);
    const [nextState, patches] = produce(state, draft => {…}, true);

    • 使用 Redux DevTools 检查状态快照 。

💎 五、总结

• 适用场景:

• 复杂嵌套状态更新(如表格数据、树形结构)。

• React/Redux 项目减少样板代码。

• 需高性能不可变操作的场景 。

• 优势:

• 简洁性:免去手动 {…spread} 操作。

• 安全性:自动防止意外修改原始数据。

• 高性能:结构共享最小化复制开销 。

通过 produce 函数和代理机制,Immer 在保持不可变数据优点的同时,提供了接近可变数据操作的开发体验,是现代化状态管理的利器。

posted @ 2025-08-22 13:45  行路客  阅读(16)  评论(0)    收藏  举报  来源