1.概述
use-immer
不屬于官方Hook
,是社區維護的第三方庫!use-immer
通過封裝 Immer 的不可變更新機制,為 React 開發者提供了一種更直觀、高效的狀態管理方式。- 它尤其適合處理復雜嵌套狀態或需要頻繁更新的場景,同時保持了與 React 原生 Hook 的兼容性。
- 對于追求代碼簡潔性和可維護性的項目,
use-immer
是一個值得嘗試的解決方案。
PS:
- 為了解決
useState
與useReducer
, 操作對象及數據非常的麻煩的問題!有了use-immer
之后就不在需要這么麻煩了!- 因為它的底層是基于 immer.js 這個庫去實現的!immer.js 庫可以高效的去復制一個對象,并且在更改新的草稿對象的時候不會修改原始對象!
- 正好合 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-immer | useState | useReducer |
---|---|---|---|
狀態更新方式 | 直接修改草稿(draft ) | 返回新狀態對象 | 返回新狀態對象 |
深層嵌套處理 | 無需手動展開,直接修改 | 需手動展開或使用工具庫(如 immer ) | 需手動展開或使用工具庫(如 immer ) |
代碼可讀性 | 高(類似直接賦值) | 低(需處理嵌套) | 中(需編寫 reducer 邏輯) |
性能優化 | 自動生成不可變更新,減少重渲染 | 依賴開發者優化 | 依賴開發者 |
何時使用 use-immer
?
場景 | 推薦 Hook |
---|---|
簡單狀態(數值、字符串) | useState |
深層嵌套對象/數組更新 | useImmer |
表單或多字段同步管理 | useImmer |
復雜狀態邏輯(如購物車) | useImmerReducer |