Zustand V5教程:Vanilla Store 与 useStore 使用详解 + 实战 Demo
Zustand 是一个轻量、灵活的状态管理库。自从 Zustand v4 推出 Vanilla Store 后,我们可以更优雅地在组件外(如 API 拦截器、工具函数)访问状态,同时在组件内继续享受响应式的状态订阅。
本教程将通过一个“登录状态管理”示例,讲解:
- Vanilla Store 和 useStore 的区别
- 如何在组件外获取状态
- 如何在组件内响应状态变化
- 实战完整代码(TypeScript + Zustand + Axios)
🧠 一图理解 Zustand 状态访问方式
场景 | 用法 | 是否响应式 | 适合位置 |
---|---|---|---|
组件内 | useStore(...) 或封装的 hook(如 useAuthToken() ) | ✅ 是 | React 组件 |
组件外 | store.getState() / store.setState() | ❌ 否 | axios、router、utils 等 |
🔧 Step 1:定义 Zustand Vanilla Store
// stores/authStore.ts
import { createStore, useStore } from "zustand";
import { persist, createJSONStorage } from "zustand/middleware";
import { immer } from "zustand/middleware/immer";interface AuthState {token: string | null;refreshToken: string | null;userId: string | null;userName: string | null;setToken: (token: string, refreshToken: string) => void;clearToken: () => void;userLogin: (data: {token: string;refreshToken: string;userId: string;userName: string;}) => void;
}export const authStore = createStore<AuthState>()(immer(persist((set) => ({token: null,refreshToken: null,userId: null,userName: null,setToken: (token, refreshToken) => set({ token, refreshToken }),clearToken: () =>set({token: null,refreshToken: null,userId: null,userName: null,}),userLogin: (userData) => {const { token, refreshToken, userId, userName } = userData;set({ token, refreshToken, userId, userName });},}),{name: "auth-storage",storage: createJSONStorage(() => localStorage),partialize: (state) => ({token: state.token,refreshToken: state.refreshToken,userId: state.userId,userName: state.userName,}),}))
);// 自定义 Hook
export const useAuthStore = <T>(selector: (state: AuthState) => T): T =>useStore(authStore, selector);export const useAuthToken = () =>useAuthStore((state) => state.token);export const useAuthUser = () =>useAuthStore((state) => ({userId: state.userId,userName: state.userName,}));export const useAuthActions = () =>useAuthStore((state) => ({login: state.userLogin,logout: state.clearToken,setToken: state.setToken,}));// 外部访问方法
export const getAuthState = () => authStore.getState();
export const setAuthState = authStore.setState;
🚀 Step 2:axios 中使用 token(非组件内)
// utils/axios.ts
import axios from "axios";
import { getAuthState } from "@/stores/authStore";const instance = axios.create({baseURL: "/api",timeout: 10000,
});instance.interceptors.request.use((config) => {const token = getAuthState().token;if (token) {config.headers.Authorization = `Bearer ${token}`;}return config;
});export default instance;
✅ 注意:我们没有用 **useAuthStore()**
,因为拦截器不是 React 环境,不能使用 Hooks!
🧩 Step 3:React 组件中响应状态
// components/UserProfile.tsx
import React from "react";
import { useAuthUser, useAuthActions } from "@/stores/authStore";const UserProfile = () => {const { userId, userName } = useAuthUser();const { logout } = useAuthActions();return (<div><p>用户:{userName} (ID: {userId})</p><button onClick={logout}>退出登录</button></div>);
};
当 userName
或 userId
发生变化时,组件会自动刷新。
🎯 总结
你要做什么 | 推荐用法 |
---|---|
React 组件内使用 token | useAuthToken() |
React 组件内使用 user 信息 | useAuthUser() |
React 中调用登录/登出方法 | useAuthActions() |
在 axios、工具函数中获取 token | authStore.getState().token 或封装的 getAuthState() |
在外部设置状态 | authStore.setState() 或封装的 setAuthState() |