【React】use-immer vs 原生 Hook:誰更勝一籌?

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時代躍遷的核心邏輯:千比特突破非為直接…