当前位置: 首页 > news >正文

Zustand

下面,我们来系统的梳理关于 Zustand 状态管理 的基本知识点:


一、Zustand 概述

1.1 什么是 Zustand?

Zustand(德语中意为“状态”)是一个轻量级、快速且可扩展的 React 状态管理库。它由 React 社区的知名开发者(React Spring 的创建者)开发,旨在提供简单高效的全局状态管理解决方案。

1.2 为什么选择 Zustand?

  • 极简 API:只需几行代码即可创建 store
  • 无样板代码:不需要 Provider 包裹组件
  • 高性能:精确的组件更新,避免不必要的重渲染
  • 轻量级:核心库仅约 1kB(gzipped)
  • 灵活性强:支持中间件、TypeScript 和 React 并发模式
  • 开发体验好:内置 DevTools 支持

1.3 核心特点

  • 基于 Hook 的状态管理
  • 不可变状态更新
  • 支持异步操作
  • 中间件系统
  • 零依赖

二、核心概念

2.1 Store

Store 是 Zustand 的核心概念,是一个包含状态和操作状态的方法的对象。

import create from 'zustand'const useStore = create((set) => ({count: 0,increment: () => set((state) => ({ count: state.count + 1 })),decrement: () => set((state) => ({ count: state.count - 1 })),
}))

2.2 Set 函数

用于更新状态的函数,类似于 React 的 setState:

set(state => ({ ...state, count: state.count + 1 }))

2.3 Get 函数

在 store 内部获取当前状态:

const useStore = create((set, get) => ({count: 0,logCount: () => {console.log(`Current count: ${get().count}`)}
}))

三、基本用法

3.1 安装

npm install zustand
# 或
yarn add zustand

3.2 创建 Store

import create from 'zustand'const useCounterStore = create((set) => ({count: 0,increment: () => set((state) => ({ count: state.count + 1 })),decrement: () => set((state) => ({ count: state.count - 1 })),reset: () => set({ count: 0 }),
}))

3.3 在组件中使用

function Counter() {const { count, increment, decrement } = useCounterStore()return (<div><h1>{count}</h1><button onClick={increment}>+</button><button onClick={decrement}>-</button></div>)
}

3.4 选择部分状态

避免不必要的重渲染:

function IncrementButton() {const increment = useCounterStore(state => state.increment)return <button onClick={increment}>+</button>
}

四、高级特性

4.1 中间件

Zustand 提供强大的中间件系统:

4.1.1 持久化中间件
import create from 'zustand'
import { persist } from 'zustand/middleware'const useAuthStore = create(persist((set) => ({user: null,login: (user) => set({ user }),logout: () => set({ user: null }),}),{name: 'auth-storage', // 存储键名getStorage: () => localStorage, // 存储引擎}
))
4.1.2 Immer 中间件

简化不可变更新:

import create from 'zustand'
import { immer } from 'zustand/middleware/immer'const useUserStore = create(immer((set) => ({user: {name: 'John',address: {city: 'New York',zip: '10001'}},updateCity: (city) => set(state => {state.user.address.city = city})
})))
4.1.3 Redux DevTools 集成
import create from 'zustand'
import { devtools } from 'zustand/middleware'const useStore = create(devtools((set) => ({count: 0,increment: () => set(state => ({ count: state.count + 1 }))
})))

4.2 异步操作

const useProductsStore = create((set) => ({products: [],loading: false,error: null,fetchProducts: async () => {set({ loading: true, error: null })try {const response = await fetch('/api/products')const products = await response.json()set({ products, loading: false })} catch (error) {set({ error: error.message, loading: false })}}
}))

4.3 计算属性

const useCartStore = create((set, get) => ({items: [],addItem: (item) => set(state => ({ items: [...state.items, item] })),removeItem: (id) => set(state => ({ items: state.items.filter(item => item.id !== id)})),get totalPrice() {return get().items.reduce((sum, item) => sum + item.price, 0)}
}))

4.4 组合 Store

// store/counter.js
export const useCounterStore = create((set) => ({count: 0,increment: () => set(state => ({ count: state.count + 1 })),
}))// store/user.js
export const useUserStore = create((set) => ({user: null,login: (user) => set({ user }),
}))// 在组件中使用
function CombinedComponent() {const count = useCounterStore(state => state.count)const user = useUserStore(state => state.user)return <div>{user.name}: {count}</div>
}

五、性能优化

5.1 精确状态选择

// 只订阅需要的状态
function UserProfile() {const user = useUserStore(state => state.user)// ...
}

5.2 使用 shallow 比较

当需要选择多个状态时:

import shallow from 'zustand/shallow'function CartSummary() {const { items, totalPrice } = useCartStore(state => ({ items: state.items, totalPrice: state.totalPrice }),shallow // 浅比较)// ...
}

5.3 批量更新

const useStore = create((set) => ({firstName: 'John',lastName: 'Doe',setFullName: (firstName, lastName) => set({ firstName, lastName })
}))

5.4 使用选择器函数

// store/selectors.js
export const selectCompletedItems = (state) => state.items.filter(item => item.completed)// 组件中使用
function CompletedItems() {const completedItems = useCartStore(selectCompletedItems)return (<ul>{completedItems.map(item => (<li key={item.id}>{item.name}</li>))}</ul>)
}

六、实践

6.1 项目结构

src/├── stores/│   ├── useAuthStore.js│   ├── useCartStore.js│   ├── useProductStore.js│   └── index.js├── components/├── hooks/└── App.js

6.2 类型安全(TypeScript)

interface CounterState {count: numberincrement: () => voiddecrement: () => void
}const useCounterStore = create<CounterState>((set) => ({count: 0,increment: () => set(state => ({ count: state.count + 1 })),decrement: () => set(state => ({ count: state.count - 1 })),
}))

6.3 测试策略

// __tests__/counterStore.test.js
import create from 'zustand'
import { act } from '@testing-library/react'test('counter store', () => {const useStore = create((set) => ({count: 0,increment: () => set(state => ({ count: state.count + 1 })),}))let stateuseStore.subscribe(s => (state = s))act(() => {useStore.getState().increment()})expect(state.count).toBe(1)
})

6.4 状态设计原则

  1. 单一职责:每个 store 关注单一领域
  2. 最小化状态:只存储必要数据
  3. 派生数据:使用 getter 或选择器
  4. 操作集中:将业务逻辑放在 store 中

七、与其他状态库对比

特性ZustandReduxRecoilContext
包大小~1kB~5kB~14kBReact 内置
学习曲线简单陡峭中等简单
性能
DevTools支持优秀支持
中间件支持支持
异步支持原生需中间件原生原生
TypeScript优秀优秀优秀良好

八、案例:电商应用

8.1 认证 Store

// stores/useAuthStore.js
import create from 'zustand'
import { persist } from 'zustand/middleware'export const useAuthStore = create(persist((set) => ({user: null,token: null,isAuthenticated: false,login: async (credentials) => {const response = await fetch('/api/login', {method: 'POST',body: JSON.stringify(credentials)})const { user, token } = await response.json()set({ user, token, isAuthenticated: true })},logout: () => {set({ user: null, token: null, isAuthenticated: false })}}),{name: 'auth-store',getStorage: () => localStorage,}
))

8.2 购物车 Store

// stores/useCartStore.js
import create from 'zustand'
import { immer } from 'zustand/middleware/immer'export const useCartStore = create(immer((set, get) => ({items: [],loading: false,error: null,addItem: (product) => {const existingItem = get().items.find(item => item.id === product.id)if (existingItem) {set(state => {const item = state.items.find(item => item.id === product.id)item.quantity += 1})} else {set(state => { state.items.push({ ...product, quantity: 1 }) })}},removeItem: (id) => {set(state => {state.items = state.items.filter(item => item.id !== id)})},updateQuantity: (id, quantity) => {if (quantity < 1) {get().removeItem(id)return}set(state => {const item = state.items.find(item => item.id === id)if (item) item.quantity = quantity})},get totalItems() {return get().items.reduce((sum, item) => sum + item.quantity, 0)},get totalPrice() {return get().items.reduce((sum, item) => sum + item.price * item.quantity, 0)},clearCart: () => set({ items: [] }),
}))

8.3 产品列表 Store

// stores/useProductStore.js
import create from 'zustand'export const useProductStore = create((set) => ({products: [],featuredProducts: [],loading: false,error: null,filters: {category: 'all',sort: 'price-asc',search: '',},fetchProducts: async () => {set({ loading: true, error: null })try {const response = await fetch('/api/products')const products = await response.json()set({ products, loading: false })} catch (error) {set({ error: 'Failed to load products', loading: false })}},fetchFeatured: async () => {set({ loading: true })try {const response = await fetch('/api/products/featured')const featured = await response.json()set({ featuredProducts: featured, loading: false })} catch {set({ loading: false })}},setFilter: (filter, value) => {set(state => ({filters: { ...state.filters, [filter]: value }}))},get filteredProducts() {return (state) => {const { products, filters } = statelet result = [...products]if (filters.category !== 'all') {result = result.filter(p => p.category === filters.category)}if (filters.search) {const searchTerm = filters.search.toLowerCase()result = result.filter(p => p.name.toLowerCase().includes(searchTerm) || p.description.toLowerCase().includes(searchTerm)}if (filters.sort === 'price-asc') {result.sort((a, b) => a.price - b.price)} else if (filters.sort === 'price-desc') {result.sort((a, b) => b.price - a.price)}return result}}
}))

8.4 组件集成示例

// components/ProductList.jsx
import { useProductStore } from '../stores/useProductStore'
import { useCartStore } from '../stores/useCartStore'function ProductList() {const { products, loading, error, setFilter } = useProductStore()const addToCart = useCartStore(state => state.addItem)if (loading) return <div>Loading products...</div>if (error) return <div>Error: {error}</div>return (<div><div className="filters"><select onChange={(e) => setFilter('category', e.target.value)}><option value="all">All Categories</option><option value="electronics">Electronics</option><option value="clothing">Clothing</option></select></div><div className="product-grid">{products.map(product => (<div key={product.id} className="product-card"><h3>{product.name}</h3><p>${product.price}</p><button onClick={() => addToCart(product)}>Add to Cart</button></div>))}</div></div>)
}// components/CartIcon.jsx
import { useCartStore } from '../stores/useCartStore'function CartIcon() {const totalItems = useCartStore(state => state.totalItems)return (<div className="cart-icon"><span>🛒</span>{totalItems > 0 && <span className="badge">{totalItems}</span>}</div>)
}

九、总结

9.1 Zustand 核心优势

  1. 极简 API:学习成本低,易于上手
  2. 高性能:精确的状态订阅机制
  3. 灵活扩展:强大的中间件系统
  4. 无 Provider 负担:简化应用结构
  5. TypeScript 友好:完整的类型支持

9.2 实践总结

  • 单一职责 Store:每个 store 关注单一领域
  • 精确状态选择:避免不必要的重渲染
  • 合理使用中间件:持久化、Immer 等
  • 类型安全:使用 TypeScript 增强可靠性
  • 模块化组织:按功能拆分 store
  • 测试驱动:编写 store 单元测试

9.3 适用场景

  • 中小型应用的状态管理
  • 需要轻量级解决方案
  • 希望避免复杂样板代码
  • 需要快速开发迭代
  • 对性能要求较高的应用
http://www.dtcms.com/a/317673.html

相关文章:

  • 从代码学习深度强化学习 - 模仿学习 PyTorch版
  • 【数据库】MySQL详解:关系型数据库的王者
  • MySQL和Navicat Premium的安装
  • stm32项目(22)——基于stm32的智能病房监护系统
  • Python面试题及详细答案150道(01-15) -- 基础语法篇
  • 代数——第6章——对称性(Michael Artin)
  • vue3 find 数组查找方法
  • CPP网络编程-异步sever
  • FPGA学习笔记——VGA彩条显示
  • python:非常流行和重要的Python机器学习库scikit-learn 介绍
  • STM32学习笔记3-GPIO输入部分
  • WMS及UI渲染底层原理学习
  • 【STM32 LWIP配置】STM32H723ZG + Ethernet +LWIP 配置 cubemx
  • 无人机图传的得力助手:5G 便携式多卡高清视频融合终端的协同应用
  • 中宇联5G云宽带+4G路由器:解锁企业办公高效协同与门店体验升级
  • 图解 Claude Code 子智能体 Sub-agent
  • [ java GUI ] 图形用户界面
  • 【软考系统架构设计师备考笔记4】 - 英语语法一篇通
  • ctfshow_vip题目限免-----SVN漏洞,git泄露
  • Git Cherry-Pick 指南
  • Leetcode——菜鸟笔记1
  • Git 分支管理:从新开发分支迁移为主分支的完整指南
  • 鸿蒙app 开发中 全局弹窗类的封装 基于PromptAction
  • C#之基础语法
  • 机器学习之朴素贝叶斯
  • Suno API V5模型 php源码 —— 使用灵感模式进行出创作
  • 基于PHP的论坛社交网站系统开发与设计
  • 排序算法详解
  • 媒体资产管理系统和OCR文字识别的结合
  • Ethereum: L1 与 L2 的安全纽带, Rollups 技术下的协作与区别全解析