admin管理员组文章数量:1443654
Zustand 用法记录
Zustand 可以做什么?
- 全局单例
- 组件间数据共选
- 替代 useState
安装
代码语言:bash复制npm install zustand
npm install --save-dev typescript @types/react
基本用法
示例:创建一个共享的计数器。
目录结构
代码语言:plain复制src/
├── components/
│ └── CounterComponent.tsx
├── stores/
│ └── useCounterStore.ts
└── index.tsx
代码语言:ts复制// store.ts
import create from 'zustand';
// 定义状态的类型
interface CounterState {
counter: number;
increment: () => void;
decrement: () => void;
data: null | any;
isLoading: boolean;
fetchData: () => Promise<void>;
}
// 创建状态存储
const useCounterStore = create<CounterState>((set) => ({
counter: 0,
increment: () => set((state) => ({ counter: state.counter + 1 })),
decrement: () => set((state) => ({ counter: state.counter - 1 })),
data: null,
isLoading: false,
fetchData: async () => {
set({ isLoading: true });
try {
const response = await fetch('');
const result = await response.json();
set({ data: result, isLoading: false });
} catch (error) {
set({ isLoading: false });
console.error('Error fetching data:', error);
}
},
}));
export default useCounterStore;
代码语言:ts复制// CounterComponent.tsx
import React from 'react';
import useCounterStore from './useCounterStore';
const CounterComponent: React.FC = () => {
const counter = useCounterStore((state) => state.counter);
const increment = useCounterStore((state) => state.increment);
const decrement = useCounterStore((state) => state.decrement);
const data = useCounterStore((state) => state.data);
const isLoading = useCounterStore((state) => state.isLoading);
const fetchData = useCounterStore((state) => state.fetchData);
return (
<div>
<h1>计数器: {counter}</h1>
<button onClick={increment}>增加</button>
<button onClick={decrement}>减少</button>
<hr />
{isLoading ? (
<p>正在加载...</p>
) : data ? (
<pre>{JSON.stringify(data, null, 2)}</pre>
) : (
<button onClick={fetchData}>获取数据</button>
)}
</div>
);
};
export default CounterComponent;
如何更新状态?
借助 set 方法,实现状态更新。set 对象可以接收对象或者方法。
使用对象更新状态
代码语言:ts复制import create from 'zustand';
// 定义状态类型
interface BearState {
bears: number;
increasePopulation: () => void;
removeAllBears: () => void;
}
// 创建状态存储
const useBearStore = create<BearState>((set) => ({
bears: 0,
// 增加熊的数量
increasePopulation: () => set({ bears: (state) => state.bears + 1 }),
// 移除所有熊
removeAllBears: () => set({ bears: 0 }),
}));
export default useBearStore;
使用函数更新状态
代码语言:ts复制import create from 'zustand';
interface CounterState {
counter: number;
increment: () => void;
decrement: () => void;
}
const useCounterStore = create<CounterState>((set) => ({
counter: 0,
// 增加计数器的值
increment: () => set((state) => ({ counter: state.counter + 1 })),
// 减少计数器的值
decrement: () => set((state) => ({ counter: state.counter - 1 })),
}));
export default useCounterStore;
异步状态更新
适合数据请求等不得不异步的操作,比如数据初始化
代码语言:ts复制import create from 'zustand';
interface DataState {
data: null | any;
isLoading: boolean;
error: null | string;
fetchData: () => Promise<void>;
}
const useDataStore = create<DataState>((set) => ({
data: null,
isLoading: false,
error: null,
// 异步获取数据
fetchData: async () => {
set({ isLoading: true, error: null });
try {
const response = await fetch('');
if (!response.ok) {
throw new Error('Network response was not ok');
}
const result = await response.json();
set({ data: result, isLoading: false });
} catch (err) {
set({ error: err.message, isLoading: false });
}
},
}));
export default useDataStore;
批量更新状态
代码语言:ts复制import create from 'zustand';
interface UserState {
name: string;
age: number;
updateUser: (newName: string, newAge: number) => void;
}
const useUserStore = create<UserState>((set) => ({
name: 'John',
age: 30,
// 批量更新用户信息
updateUser: (newName, newAge) => set({ name: newName, age: newAge }),
}));
export default useUserStore;
如何状态很多,Store变得过于复杂怎么办?
- 拆分状态
- 浅比较和选择性订阅
- 使用 immer 进行不可变更新
- 异步操作优化
- 模块化和可复用性
- 拆分状态
将复杂对象拆分成多个小的状态存储,避免单个存储变得过于庞大。例如,若有一个用户对象包含基本信息、偏好设置和订单信息,可将这些信息拆分成不同的存储。
代码语言:ts复制import create from 'zustand';
// 用户基本信息存储
interface UserBasicInfo {
name: string;
age: number;
updateName: (newName: string) => void;
updateAge: (newAge: number) => void;
}
const useUserBasicInfoStore = create<UserBasicInfo>((set) => ({
name: 'John',
age: 30,
updateName: (newName) => set({ name: newName }),
updateAge: (newAge) => set({ age: newAge }),
}));
// 用户偏好设置存储
interface UserPreferences {
theme: string;
language: string;
updateTheme: (newTheme: string) => void;
updateLanguage: (newLanguage: string) => void;
}
const useUserPreferencesStore = create<UserPreferences>((set) => ({
theme: 'light',
language: 'en',
updateTheme: (newTheme) => set({ theme: newTheme }),
updateLanguage: (newLanguage) => set({ language: newLanguage }),
}));
export { useUserBasicInfoStore, useUserPreferencesStore };
- 浅比较和选择性订阅
Zustand 默认使用浅比较来判断状态是否改变,只有状态发生改变时,订阅该状态的组件才会重新渲染。同时,你可以选择性地订阅状态的部分属性,避免不必要的重新渲染。
代码语言:ts复制import React from 'react';
import { useUserBasicInfoStore } from './stores';
const UserNameComponent: React.FC = () => {
// 仅订阅 name 属性
const name = useUserBasicInfoStore((state) => state.name);
return (
<div>
<p>User Name: {name}</p>
</div>
);
};
export default UserNameComponent;
- 使用 immer 进行不可变更新
处理复杂对象的嵌套更新时,使用 immer 库可以让代码更简洁,同时确保状态更新的不可变性。
代码语言:bash复制npm install immer
代码语言:ts复制import create from 'zustand';
import produce from 'immer';
interface NestedState {
nested: {
prop1: string;
prop2: number;
};
updateNestedProp1: (newValue: string) => void;
}
const useNestedStateStore = create<NestedState>((set) => ({
nested: {
prop1: 'value1',
prop2: 10,
},
updateNestedProp1: (newValue) =>
set(
produce((state) => {
state.nested.prop1 = newValue;
})
),
}));
export default useNestedStateStore;
- 异步操作优化
对于复杂对象的异步更新,可采用中间件或自定义逻辑来优化。例如,在请求数据时,可使用防抖或节流来减少不必要的请求。
代码语言:ts复制import create from 'zustand';
import { debounce } from 'lodash';
interface AsyncDataState {
data: any;
isLoading: boolean;
error: null | string;
fetchData: (query: string) => void;
}
const useAsyncDataStore = create<AsyncDataState>((set) => {
const fetchDataDebounced = debounce(async (query) => {
set({ isLoading: true, error: null });
try {
const response = await fetch(`=${query}`);
if (!response.ok) {
throw new Error('Network response was not ok');
}
const result = await response.json();
set({ data: result, isLoading: false });
} catch (err) {
set({ error: err.message, isLoading: false });
}
}, 300);
return {
data: null,
isLoading: false,
error: null,
fetchData: (query) => fetchDataDebounced(query),
};
});
export default useAsyncDataStore;
- 模块化和可复用性
将状态管理逻辑封装成可复用的模块,方便在不同组件中使用。例如,创建一个通用的列表管理模块。
代码语言:ts复制import create from 'zustand';
interface ListState<T> {
items: T[];
addItem: (item: T) => void;
removeItem: (index: number) => void;
}
const createListStore = <T>() =>
create<ListState<T>>((set) => ({
items: [],
addItem: (item) => set((state) => ({ items: [...state.items, item] })),
removeItem: (index) =>
set((state) => ({
items: state.items.filter((\_, i) => i !== index),
})),
}));
// 创建一个存储字符串列表的状态
const useStringListStore = createListStore<string>();
export { useStringListStore };
通过上述优化策略,可以更高效地使用 Zustand 管理复杂对象,提升应用的性能和可维护性。
用 Selector 优化性能
Selector 用来从复杂状态中,挑出你需要的部分。
简单示例:selectTotalPrice 函数根据 items 数组计算购物车的总价格,组件只需要订阅这个派生状态即可。
代码语言:ts复制import create from 'zustand';
interface ShoppingCartState {
items: { id: number; name: string; price: number; quantity: number }[];
addItem: (item: { name: string; price: number; quantity: number }) => void;
}
const useShoppingCartStore = create<ShoppingCartState>((set) => ({
items: [],
addItem: (item) =>
set((state) => ({
items: [...state.items, { ...item, id: Date.now() }],
})),
}));
const selectTotalPrice = (state: ShoppingCartState) =>
state.items.reduce((total, item) => total + item.price \* item.quantity, 0);
const ShoppingCartSummary = () => {
const totalPrice = useShoppingCartStore(selectTotalPrice);
return <p>Total Price: ${totalPrice}</p>;
};
export default ShoppingCartSummary;
本文标签: Zustand 用法记录
版权声明:本文标题:Zustand 用法记录 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/biancheng/1748161711a2819172.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论