.所有页面都能访问和修改 tab 状态
// 定义单个 tab 的结构 interface TabItem { id: string title: string } // 堆代码 duidaima.com // 整个 store 的结构 interface TabState { tabs: TabItem[] currentTabId: string addTab: (tab: TabItem) =>void removeTab: (id: string) =>void setCurrentTab: (id: string) =>void }然后用 Zustand 创建一个 store:
import { create } from 'zustand' export const useTabStore = create<TabState>((set) => ({ tabs: [], currentTabId: '', addTab: (tab) => set((state) => ({ tabs: [...state.tabs, tab] })), removeTab: (id) => set((state) => ({ tabs: state.tabs.filter((t) => t.id !== id), currentTabId: state.currentTabId === id ? '' : state.currentTabId })), setCurrentTab: (id) => set({ currentTabId: id }) }))是不是很简洁?一个 create() 函数就搞定共享状态,类型提示也直接到位。
import { useTabStore } from'./store/tabStore' exportdefaultfunction TabView() { const { tabs, currentTabId, addTab, setCurrentTab } = useTabStore() return ( <div> <button onClick={() => addTab({ id: 'settings', title: '设置' })}> 新增 Tab </button> <div style={{ display: 'flex', gap: 8 }}> {tabs.map((tab) => ( <div key={tab.id} onClick={() => setCurrentTab(tab.id)} style={{ padding: 4, borderBottom: tab.id === currentTabId ? '2px solid blue' : 'none', cursor: 'pointer' }} > {tab.title} </div> ))} </div> </div> ) }现在这个组件可以随时新增 Tab、切换当前 Tab,所有状态都由 Zustand 管理,其他组件也能随时访问它,非常方便。
import { create } from'zustand'; // 创建一个包含多个字段的状态 const useAppStore = create((set) => ({ // 用户信息 user: { name: '张三', age: 25, isLogin: true }, // 主题设置 theme: 'light', // 修改主题的方法 setTheme: (newTheme) =>set({ theme: newTheme }), // 修改用户年龄的方法 setUserAge: (age) =>set((state) => ({ user: { ...state.user, age } })) }));如果组件直接订阅整个状态对象,即使只用到其中一个字段,当状态中任何字段变化时,组件都会重新渲染:
// 组件 A:只需要显示用户名 function UserName() { // 订阅了整个状态对象(错误示范) const { user } = useAppStore(); console.log('UserName 组件渲染了'); return <div>用户名:{user.name}</div>; } // 组件 B:只需要显示主题 function ThemeDisplay() { // 同样订阅了整个状态对象( const { theme } = useAppStore(); console.log('ThemeDisplay 组件渲染了'); return <div>当前主题:{theme}</div>; }当调用 setUserAge(26) 修改用户年龄时,user 对象变化 → 即使 ThemeDisplay 只用到 theme(未变化),也会被强制重新渲染,控制台会打印 ThemeDisplay 组件渲染了。
// 组件 A:只订阅 user.name function UserName() { // 精确选择需要的字段 const userName = useAppStore((state) => state.user.name); console.log('UserName 组件渲染了'); return <div>用户名:{userName}</div>; } // 组件 B:只订阅 theme function ThemeDisplay() { // 精确选择需要的字段 const theme = useAppStore((state) => state.theme); console.log('ThemeDisplay 组件渲染了'); return <div>当前主题:{theme}</div>; }当调用 setUserAge(26) 时,只有 user.age 变化,user.name 未变 → UserName 组件不会重新渲染。
当调用 setTheme('dark') 时,theme 变化 → 只有 ThemeDisplay 组件重新渲染,UserName 不受影响。
import { persist } from 'zustand/middleware' const useUserStore = create( persist( (set) => ({ token: '', setToken: (val) => set({ token: val }), }), { name: 'user-storage', // localStorage key } ) )下次页面加载会自动恢复状态,无需你手动做缓存逻辑。
import { devtools } from 'zustand/middleware' const useStore = create(devtools((set) => ({ count: 0, increase: () => set((state) => ({ count: state.count + 1 })) })))开起来直接就能调状态了,兼容性也很好。
3.模块化拆分 store,保持单一职责,一个功能一个 store 文件,利于维护和团队协作。
stores/tabStore.ts:管理多页签状态 stores/userStore.ts:管理用户登录态 stores/formStore.ts:表单缓存数据 stores/themeStore.ts:主题设置每个 Store 内部维护自己的状态结构和操作函数,只暴露对应的 useXXXStore hook。
// stores/userStore.ts interface UserState { token: string login: (token: string) => void logout: () => void } export const useUserStore = create<UserState>((set) => ({ token: '', login: (token) => set({ token }), logout: () => set({ token: '' }), }))其他组件中直接使用:
const { token, login } = useUserStore()这样做的好处是:
3.对新成员更友好,知道状态在哪改、在哪用
4.还能支持持久化、选择订阅、调试工具,非常全面
对我来说,Zustand 就是那个 刚刚好 的选择:干净利落、类型清晰、可扩展性强,非常适合中小型项目的快速开发。
附上zustand官网地址:https://github.com/pmndrs/zustand