学习React-8-useImmer

发布于:2025-09-05 ⋅ 阅读:(20) ⋅ 点赞:(0)
useImmer

useImmer是基于 immer 库实现的一个 React Hook,它让你可以像修改可变数据一样来修改不可变数据。immer 是一个不可变的数据结构库,完全符合 React 的不可变性原则。

特点
  • 可变式写法:你可以像修改可变数据一样编写代码,但实际上是在生成新的不可变数据
  • 类型安全:完全支持 TypeScript,提供良好的类型推断
  • 性能优化:使用结构共享,只修改变化的部分,其他部分保持引用不变
实现原理
immer 的核心是使用 Proxy 对象来拦截对原始数据的修改操作。当你在 produce 函数中修改数据时,immer 会记录这些修改,然后基于原始数据生成一个新的不可变对象。
使用

因为这并不是React官方的包,所以需要下载 npm install immer use-immer

小栗子

useImmer

import React from 'react';
import { useImmer, useImmerReducer } from 'use-immer';

interface User {
  name: string
  age: number
  hobby: Array<string>
  
}
interface UseImmerProps {
  pUser: User;
}

const UseImmer: React.FC<UseImmerProps> = (props) => {
  const [user, updateUser] = useImmer<User>(props.pUser);

  const handleIncreaseAge = () => {
    updateUser(draft => {
      draft.age += 1;
    });
  };

  // 操作对象的值
  const handleSetName = (name: string) => {
    updateUser(draft => {
      draft.name = name;
    });
  };

  // 操作数组的值
  const handleHobby = (name: string) => {
    updateUser(draft => {
        draft.hobby.push(name)
    })
  }

  return (
    <div>
      <p>User: {user.name}, Age: {user.age}</p>
      {user.hobby.map((item, index) => {
        return <p key={`${item}_${index}`}>{item}</p>;
      })}
      <button onClick={handleIncreaseAge}>Increase Age</button>
      <button onClick={() => handleSetName('黑子')}>Change name</button>
      <button onClick={() => handleHobby('跳舞')}>add hobby</button>
    </div>
  );
};

export default UseImmer;



// App调用
<UseImmer pUser={{name: 'kun', age: 18, hobby: ['唱歌'] }}></UseImmer>

useImmerReducer


interface State {
    count: number;
}
type Action = 
  | { type: 'INCREMENT' }
  | { type: 'DECREMENT' }

const initState = {
    count: 0
}
const counterReducer = (state: State, action: Action) => {
    switch (action.type) {
        case 'INCREMENT':
            state.count += 1;
            break;
        case 'DECREMENT':
            state.count -= 1;
            break;
    }
}
const UseImmer: React.FC<UseImmerProps> = (props) => {
  const [state, dispatch] = useImmerReducer(counterReducer, initState)

  return (
    <div>
      <button onClick={() => dispatch({ type: 'INCREMENT' })}>+</button>
      <p>Count: {state.count}</p>
      <button onClick={() => dispatch({ type: 'DECREMENT' })}>-</button>
    </div>
  );
};

export default UseImmer;
useState和useImmer对比
维度 useState(原生) useImmer(基于 Immer)
引入成本 React 自带 需安装 use-immer
基本类型 ✅ 直接 setCount(c => c + 1) ✅ 同样写法
简单对象 / 数组 ❗ 手动展开、拼接、拷贝 ✅ 直接 draft.x.y = z
深层嵌套结构 ❌ 层层解构,代码冗长易错 ✅ 按可变方式书写即可
不可变性保证 开发者完全自控 Immer 内部自动生成新引用
样板代码量
调试可读性 reducer / switch 可读性一般 逻辑扁平,更具命令式直觉
性能(简单场景) 最快 稍慢(Immer Proxy 开销)
性能(复杂场景) 可能因多次浅拷贝浪费 Immer 结构共享,反而更优
代码对比

useState —— 更新深层字段:

setState(prev => ({
  ...prev,
  user: {
    ...prev.user,
    address: {
      ...prev.user.address,
      city: 'Shanghai'
    }
  }
}));

useImmer —— 同一段逻辑:

updateState(draft => {
  draft.user.address.city = 'Shanghai';
});

网站公告

今日签到

点亮在社区的每一天
去签到