1.概述

  1. use-immer 不属于官方 Hook,是社区维护的第三方库!
  2. use-immer 通过封装 Immer 的不可变更新机制,为 React 开发者提供了一种更直观、高效的状态管理方式。
  3. 它尤其适合处理复杂嵌套状态或需要频繁更新的场景,同时保持了与 React 原生 Hook 的兼容性。
  4. 对于追求代码简洁性和可维护性的项目,use-immer 是一个值得尝试的解决方案。

PS:

  1. 为了解决 useStateuseReducer, 操作对象及数据非常的麻烦的问题!有了 use-immer 之后就不在需要这么麻烦了!
  2. 因为它的底层是基于 immer.js 这个库去实现的!immer.js 库可以高效的去复制一个对象,并且在更改新的草稿对象的时候不会修改原始对象!
  3. 正好合 React 的理念相符合!所以说在工作中更多的应用中使用最多的就是这个库。

2.安装

pnpm 或者 npm 安装

// pnpm 安装
pnpm add use-immer// npm 安装
npm install use-immer

3.使用指南

  • 以下通过多个实际场景展示 use-immer 的强大功能

  • 涵盖基础状态更新、复杂对象/数组操作、表单管理以及与 useImmerReducer 的结合使用。

3.1 基础计数器

直接修改数值

说明

  • 直接传递新值(如 count + 1)给 setCount,行为类似 useState,适合简单状态更新。
import React from "react";
import { useImmer } from "use-immer";function Counter() {const [count, setCount] = useImmer(0);return (<div><p>Count: {count}</p><button onClick={() => setCount(count + 1)}>Increment</button><button onClick={() => setCount(count - 1)}>Decrement</button></div>);
}

3.2 复杂对象更新

深层嵌套修改简化

import { useImmer } from 'use-immer';interface User {name: string;address: {city: string;zip: string;};
}function App() {const [user, updateUser] = useImmer<User>({name: "Alice",address: {city: "New York",zip: "10001",},});const updateCity = () => {updateUser(draft => {// 使用 Immer 的 draft 草稿对象直接修改嵌套的城市字段,无需手动复制其他字段draft.address.city = "Los Angeles";});};return (<div><p>Name: {user.name}</p><p>City: {user.address.city}</p><button onClick={updateCity}>Change City</button></div>);
}
export default App;

对比原生 useState

// 原生方式需手动展开所有嵌套层级
const [user, setUser] = useState(initialUser);
setUser({...user,address: {...user.address,city: "Los Angeles",},
});

3.3 处理数组

数组操作变得异常简单,所有原生数组方法都可以直接使用

import { useImmer } from 'use-immer';interface User {name: string;age: number;
}function App() {// 修正初始值类型,应为 User[] 数组类型const [arr, updatArr] = useImmer<User[]>([{name: "Alice",age: 18,}]);const updateCity = (i: User) => {updatArr(draft => {// 新增数据draft.push(i);// PS: 这里也可以直接修改值 draft[0].age = 60;});};return (<div>{Array.isArray(arr) && arr.map((item, index) => (<div key={index}><p>Name: {item.name}</p><p>Age: {item.age}</p></div>))}<button onClick={() => updateCity({ name: "Bob", age: 20 })}>Add User</button></div>);
}
export default App;

3.4 表单管理

优势

  • 无需为每个字段单独维护 useState,代码更简洁。
  • 动态字段更新(如 draft[name] = value)避免冗余逻辑。
function ContactForm() {const [form, updateForm] = useImmer({name: "",email: "",phone: "",});const handleChange = (e) => {const { name, value } = e.target;updateForm(draft => {draft[name] = value; // 动态更新任意字段});};const handleSubmit = (e) => {e.preventDefault();console.log("Form submitted:", form);};return (<form onSubmit={handleSubmit}><input name="name" value={form.name} onChange={handleChange} placeholder="Name" /><input name="email" value={form.email} onChange={handleChange} placeholder="Email" /><input name="phone" value={form.phone} onChange={handleChange} placeholder="Phone" /><button type="submit">Submit</button></form>);
}

3.5 高级场景:useImmerReducer 管理复杂状态

为什么选择 useImmerReducer

  • 集中管理相关状态逻辑
  • 避免 useReducer 中手动展开状态的繁琐操作。
import { useImmerReducer } from 'use-immer';// 定义状态类型,增加点属性
interface CounterState {name: string;age: number;
}// 定义 action 类型,增加与点属性相关的 action
type CounterAction = { type: 'increment' } | { type: 'decrement' } | { type: 'reset' };// 定义 reducer 函数,增加点属性的处理逻辑
function counterReducer(draft: CounterState, action: CounterAction): CounterState { // 增加返回值类型声明switch (action.type) {case 'increment':draft.age++;break;case 'decrement':draft.age--;break;case 'reset':draft.age = 0;break;}return draft; // 明确返回 draft
}function App() {// 使用 useImmerReducer 初始化状态,将初始化值改为对象形式,增加点属性的初始化const initialState: CounterState = { name: 'Jon', age: 18 }; // 增加类型注解const [state, dispatch] = useImmerReducer(counterReducer, initialState);const { name, age } = state;return (<div><p>姓名: {name}</p><p>年龄: {age ?? 0}</p><button onClick={() => dispatch({ type: 'increment' })}>增加</button><button onClick={() => dispatch({ type: 'decrement' })}>减少</button><button onClick={() => dispatch({ type: 'reset' })}>重置</button></div>);
}export default App;

4.总结

use-immer 通过隐藏不可变更新的复杂性,让开发者能更专注于业务逻辑,尤其适合中大型 React 项目。

use-immer 与原生 useState/useReducer 对比?

特性use-immeruseStateuseReducer
状态更新方式直接修改草稿(draft返回新状态对象返回新状态对象
深层嵌套处理无需手动展开,直接修改需手动展开或使用工具库(如 immer需手动展开或使用工具库(如 immer
代码可读性高(类似直接赋值)低(需处理嵌套)中(需编写 reducer 逻辑)
性能优化自动生成不可变更新,减少重渲染依赖开发者优化依赖开发者

何时使用 use-immer

场景推荐 Hook
简单状态(数值、字符串)useState
深层嵌套对象/数组更新useImmer
表单或多字段同步管理useImmer
复杂状态逻辑(如购物车)useImmerReducer

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/93195.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/93195.shtml
英文地址,请注明出处:http://en.pswp.cn/web/93195.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【案例】Vue3 实现高性能级横向循环滚动生产线效果:基于 requestAnimationFrame 的流畅动画方案

动画效果在工业监控系统、生产看板等场景中&#xff0c;经常需要模拟生产线的动态运行效果。本文将基于 Vue3 和 requestAnimationFrame 实现一个高性能的横向循环滚动效果&#xff0c;完美模拟生产线传输带的视觉体验。我们将从代码实现到原理分析&#xff0c;全面讲解如何打造…

万字长文解码如何玩转Prompt(附实践应用)

在AI技术迅猛发展的今天&#xff0c;如何与大型语言模型高效“对话”已成为释放其潜力的关键。本文深入探讨了提示词工程&#xff08;Prompt Engineering&#xff09;这一新兴领域&#xff0c;系统解析了从基础概念到高级技巧的完整知识体系&#xff0c;并结合“淘宝XX业务数科…

easyExcel嵌套子集合导出Excel

我想要的Excel效果说明: 1.创建两个自定义注解:ExcelMerge(表示主对象内的单个属性,后续会根据子集合的大小合并下面的单元格),ExcelNestedList(表示嵌套的子集合) 2.NestedDataConverter.java 会把查询到的数据转换为一行一行的,相当于主表 left join 子表 ON 主.id子.主id的形…

基于 C# WinForm 字体编辑器开发记录:从基础到进阶

目录 基础版本实现 进阶版本改进 字体设置窗体增强 主窗体改进 功能对比 项目在本文章的绑定资源中免费的&#xff0c;0积分就可以下载哦~ 在 Windows Forms 应用开发中&#xff0c;字体编辑功能是许多文本处理软件的基础功能。本文将分享一个简易字体编辑器的开发过程&a…

Linux基本使用和Java程序部署(含 JDK 与 MySQL)

文章目录Linux 背景知识Linux 基本使用Linux 常用的特殊符号和操作符Linux 常用命令文本处理与分析系统管理与操作用户与权限管理文件/目录操作与内容处理工具Linux系统防火墙Shell 脚本与实践搭建 Java 部署环境apt&#xff08;Debian/Ubuntu 系的包管理利器&#xff09;介绍安…

抗辐照CANFD通信芯片在高安全领域国产化替代的研究

摘要&#xff1a;随着现代科技的飞速发展&#xff0c;高安全领域如航空航天、卫星通信等对电子设备的可靠性与抗辐照性能提出了极高的要求。CANFD通信芯片作为数据传输的关键组件&#xff0c;其性能优劣直接关系到整个系统的稳定性与安全性。本文聚焦于抗辐照CANFD通信芯片在高…

Mybatis 源码解读-SqlSession 会话源码和Executor SQL操作执行器源码

作者源码阅读笔记主要采用金山云文档记录的&#xff0c;所有的交互图和代码阅读笔记都是记录在云文档里面&#xff0c;本平台的文档编辑实在不方便&#xff0c;会导致我梳理的交互图和文档失去原来的格式&#xff0c;所以整理在文档里面&#xff0c;供大家阅读交流. 【金山文档…

Java集合类综合练习题

代码 import java.util.*; class ScoreRecord {private String studentId;private String name;private String subject;private int score;public ScoreRecord(String studentId, String name, String subject, int score) {this.studentId studentId;this.name name;this.s…

秒懂边缘云|1分钟了解边缘安全加速 ESA

普通开发者如何搭建安全快速的在线业务才能性价比最高 &#xff1f;阿里云现已为开发者推出免费版边缘安全加速 ESA&#xff0c;1 个产品就能把 CDN 缓存 API 加速 DNS WAF DDoS 防护全部搞定&#xff0c;还支持边缘函数快速部署网站和 AI 应用&#xff0c;性价比拉满。 1…

数据结构:串、数组与广义表

&#x1f4cc;目录&#x1f524; 一&#xff0c;串的定义&#x1f330; 二&#xff0c;案例引入场景1&#xff1a;文本编辑器中的查找替换场景2&#xff1a;用户手机号验证&#x1f4da; 三&#xff0c;串的类型定义、存储结构及其运算&#xff08;一&#xff09;串的抽象类型定…

服务器路由相关配置Linux和Windows

服务器路由相关配置Linux和Windowscentos路由系统核心概念传统工具集(命令)iproute2 工具集&#xff08;推荐&#xff09;NetworkManager 工具路由配置文件体系高级路由功能策略路由多路径路由路由监控工具系统级路由配置启用IP转发路由守护进程路由问题诊断流程Windows 路由Wi…

Spring Boot启动事件详解:类型、监听与实战应用

1. Spring Boot启动事件概述1.1 什么是Spring Boot启动事件在Spring Boot的应用生命周期中&#xff0c;从main方法执行到应用完全就绪&#xff0c;期间会发生一系列事件&#xff08;Event&#xff09;。这些事件由Spring Boot框架在特定时间点触发&#xff0c;用于通知系统当前…

Python闭包详解:理解闭包与可变类型和不可变类型的关系

一、定义闭包&#xff08;Closure&#xff09; 指的是一个函数对象&#xff0c;即使其外部作用域的变量已经不存在了&#xff0c;仍然能访问这些变量。简单来说&#xff0c;闭包是由函数及其相关的环境变量组成的实体。def outer():x 10def inner():print(x)return innerf ou…

BotCash:GPT-5发布观察 工程优化的进步,还是技术突破的瓶颈?

BotCash&#xff1a;GPT-5发布观察 工程优化的进步&#xff0c;还是技术突破的瓶颈&#xff1f; 在GPT-4以多模态能力震撼业界的一年后&#xff0c;GPT-5的亮相显得有些“平静”。当人们期待着又一场颠覆性技术革命时&#xff0c;这场发布会更像是给大模型技术按下了“精细打磨…

AJAX学习(2)

目录 一.XMLHttpRequest 二.XMLHttpRequest——查询参数 三.案例——地区查询 四.XMLHttpRequest_数据提交 五.Promise 六.Promise三种状态 七.PromiseeeXHR获取省份列表&#xff08;案例&#xff09; 八.封装-简易axios-获取省份列表 九.封装-简易axios-获取地区列表 …

解决 pip 安装包时出现的 ReadTimeoutError 方法 1: 临时使用镜像源(单次安装)

解决 pip 安装包时出现的 ReadTimeoutError 当您在使用 pip 安装 Python 包时遇到 pip._vendor.urllib3.exceptions.ReadTimeoutError: HTTPSConnectionPool(hostfiles.pythonhosted.org, port443): Read timed out. 错误时&#xff0c;这通常是由于网络问题导致的连接超时。P…

Linux下使用Samba 客户端访问 Samba 服务器的配置(Ubuntu Debian)

在 Linux 系统中&#xff0c;Samba 提供了与 Windows 系统文件共享的便利方式。本文将详细介绍在 Ubuntu 和 Debian 系统下如何安装 Samba 客户端、访问共享资源&#xff0c;并实现远程目录挂载和开机自动挂载。 文章参考自&#xff08;感谢分享&#xff09;&#xff1a;https…

解决dedecms文章默认关键字太短的问题

在管理文章或软件的时候&#xff0c;大家在添加关键字和内容摘要的时候&#xff0c;是不是对这样的情况感到比较的郁闷&#xff0c;我的关键字设定的明明非常的好&#xff0c;可是添加或修改后&#xff0c;会被无缘无故的截去很多&#xff0c;想必大家也都非常的明白&#xff0…

K8s-kubernetes(二)资源限制-详细介绍

K8s如何合理规定对象资源使用 基本概念 Kubernetes中&#xff0c;占用资源的最小单元为单个PodKubernetes中&#xff0c;资源占用主要针对服务器的CPU、内存 为什么要做资源限制 对于Kubernetes集群而言&#xff0c;所有Pod都会占用K8s集群所在服务器的资源&#xff0c;如果不做…

量子神经网络:从NISQ困境到逻辑比特革命的破局之路

——解析2025千比特时代开发者的机遇与行动框架 引言:量子计算的“20比特魔咒”与千比特悖论 当开发者被建议“避免在>20量子比特电路训练”时,富士通却宣布2025年实现10,000物理比特系统。这一矛盾揭示了量子计算从NISQ时代向FTQC时代跃迁的核心逻辑:千比特突破非为直接…