[react] useImmer 和 useImmerReducer

35 阅读2分钟

npm install immer use-immer

1️⃣ 概念

useImmer

  • 来自 Immer 库。
  • 作用:让你在 React state 中可以 直接“修改(操作)”对象或数组,而不需要手动写展开运算符(...)。
  • 内部原理:Immer 会帮你在后台生成一个新的 immutable state,所以你看起来像是直接修改,但其实是不可变更新。

本质:简化复杂 state 的更新,尤其是嵌套对象/数组。


useImmerReducer

  • 和 React 原生的 useReducer 类似,但使用 Immer,让 reducer 内可以直接修改 state。
  • 传统 useReducer 要返回一个新对象:
return {...state, nested: {...state.nested, value: newValue}}
  • 使用 useImmerReducer 可以直接写:
state.nested.value = newValue

Immer 会帮你生成新的 state。

本质:把 reducer 的不可变更新变成“可变写法”,减少样板代码。


2️⃣ 基本用法

(1)useImmer

import { useImmer } from "use-immer";

function Counter() {
  // state 是一个对象
  const [state, updateState] = useImmer({ count: 0, nested: { value: 10 } });

  const increment = () => {
    updateState(draft => {
      draft.count += 1;          // 直接修改
      draft.nested.value += 5;   // 嵌套对象也可以直接修改
    });
  };

  return (
    <div>
      <p>Count: {state.count}</p>
      <p>Nested Value: {state.nested.value}</p>
      <button onClick={increment}>Increment</button>
    </div>
  );
}

✅ 优点:

  • 可以直接写 draft.count += 1,不需要写 ...state
  • 嵌套对象/数组修改也很简洁。

(2)useImmerReducer

import { useImmerReducer } from "use-immer";

const initialState = {
  count: 0,
  todos: []
};

function reducer(state, action) {
  switch (action.type) {
    case "increment":
      state.count += 1;  // 直接修改
      break;
    case "addTodo":
      state.todos.push(action.payload); // 直接 push
      break;
    default:
      break;
  }
}

function App() {
  const [state, dispatch] = useImmerReducer(reducer, initialState);

  return (
    <div>
      <p>Count: {state.count}</p>
      <button onClick={() => dispatch({ type: "increment" })}>Increment</button>
      <button onClick={() => dispatch({ type: "addTodo", payload: "Learn Immer" })}>
        Add Todo
      </button>
      <ul>
        {state.todos.map((todo, i) => (
          <li key={i}>{todo}</li>
        ))}
      </ul>
    </div>
  );
}

✅ 优点:

  • reducer 写法和普通可变 JS 一样。
  • 嵌套更新也非常简单,无需深拷贝。

3️⃣ 总结对比

Feature原生 useState / useReduceruseImmer / useImmerReducer
更新对象/数组需要深拷贝或展开运算符 ...可以直接修改 draft
嵌套 state 更新很麻烦,需要手动拷贝每一层自动生成新 state,直接修改即可
API[state, setState] / [state, dispatch][state, updateState] / [state, dispatch]
使用场景简单 state 更新嵌套对象/数组,复杂 state 更新

💡 小技巧

  • 如果 state 很简单,useState 更轻量。
  • 如果 state 很复杂,尤其是嵌套对象、数组频繁修改,useImmer 能极大减少代码量和 bug。