Zustand状态库(简洁、强大、易用的React状态管理工具)

Zustand状态库(简洁、强大、易用的React状态管理工具)

1、Zustand状态管理认识

Zustand 是一个轻量级的状态管理库,非常适合用于管理全局状态,包括用户认证信息在React项目之中,接下来我们就在项目中进行使用。

🍎官网

JS 复制代码
Zustand官网
https://zustand.docs.pmnd.rs/getting-started/introduction

Zustand中文官网
https://awesomedevin.github.io/zustand-vue/docs/introduce/start/zustand

🍎选择它的原因

小型项目我们使用了Zustand,而不是庞大的Redux

React项目中,组件状态管理通常如下

  1. 组件内状态:小型项目中使用useState足矣
  2. Context传递:中型项目通过Context共享状态
  3. 全局状态管理:大型项目需要集中式状态管理

2、安装使用

javascript 复制代码
yarn add zustand


安装以后查看一下自己的版本
我本地版本
"zustand": "^5.0.8"

🍎Zustand非持久化使用

接下来我们一步一步使用 Zustand 来保存登录的 token 信息,并实现登录和退出功能。

javascript 复制代码
src\store\userStore.ts

// src/store/authStore.ts
import { create } from 'zustand';

interface AuthState {
  token: string | null;
  user: any | null;
  isAuthenticated: boolean;
  login: (token: string, user?: any) => void;
  logout: () => void;
  loading: boolean;
  setLoading: (loading: boolean) => void;
}

// 直接创建 store
export const useAuthStore = create<AuthState>((set) => ({
  token: null,
  user: null,
  isAuthenticated: false,
  loading: true,
  
  // 登录函数
  login: (token, user) => {
    set({ token, user, isAuthenticated: true });
  },
  
  // 退出函数
  logout: () => {
    set({ token: null, user: null, isAuthenticated: false });
  },
  
  // 设置加载状态
  setLoading: (loading) => {
    set({ loading });
  },
}));

🍎测试一下我们的登录状态

javascript 复制代码
// src/components/AuthStatus.tsx
import React from 'react';
import { useAuthStore } from '@/store/authStore';

export const AuthStatus=() => {
  const { token, user, isAuthenticated, loading, login, logout } = useAuthStore();
  const handleLogin = () => {
    // 模拟登录
    login('fake-jwt-token', { id: 1, name: 'John Doe', email: 'john@example.com' });
  };
  const handleLogout = () => {
    // 模拟退出
    logout();
  };
  return (
    <div>
      <h2>认证状态</h2>
      <p>是否已认证: {isAuthenticated ? '是' : '否'}</p>
      <p>Token: {token || '无'}</p>
      {user && (
        <div>
          <p>用户ID: {user.id}</p>
          <p>用户名: {user.name}</p>
          <p>邮箱: {user.email}</p>
        </div>
      )}
      <div style={{ marginTop: '16px' }}>
        {!isAuthenticated ? (
          <button onClick={handleLogin}>模拟登录</button>
        ) : (
          <button onClick={handleLogout}>退出登录</button>
        )}
      </div>
    </div>
  );
};

export default AuthStatus;

这时候我们还没写localStorage存储,那么会导致什么问题呢

刷新页面以后

store 中的状态将不会自动保存到 localStorage 中,页面刷新后状态会重置为初始值。

🍎手动处理 token

接下来我们手动处理 token 的持久化(例如,只持久化 token 而不持久化其他状态)

你可以在登录和退出函数中手动处理 localStorage 的读写

javascript 复制代码
// src/store/authStore.ts
import { create } from 'zustand';

interface AuthState {
  token: string | null;
  user: any | null;
  isAuthenticated: boolean;
  login: (token: string, user?: any) => void;
  logout: () => void;
  loading: boolean;
  setLoading: (loading: boolean) => void;
}

export const useAuthStore = create<AuthState>((set) => ({
  token: localStorage.getItem('token'), // 初始化时从 localStorage 读取
  user: null,
  isAuthenticated: !!localStorage.getItem('token'), // 根据 token 是否存在设置认证状态
  loading: true,
  
  // 登录函数
  login: (token, user) => {
    // 将 token 保存到 localStorage
    localStorage.setItem('token', token);
    set({ token, user, isAuthenticated: true });
  },
  
  // 退出函数
  logout: () => {
    // 从 localStorage 移除 token
    localStorage.removeItem('token');
    set({ token: null, user: null, isAuthenticated: false });
  },
  
  // 设置加载状态
  setLoading: (loading) => {
    set({ loading });
  },
}));

🍎持久化的中间件 persist 中间件

这个时候我们刷新会发现只持久化 token,而其他状态(如 user 和 loading)不会持久化,页面刷新后会重置为初始值

这个时候就需要用到zustand持久化的中间件persist以及createJSONStorage

javascript 复制代码
import { create } from 'zustand';
import { persist } from 'zustand/middleware';

const useStore = create(
  persist(
    (set) => ({
      count: 0,
      increment: () => set((state) => ({ count: state.count + 1 })),
    }),
    {
      name: 'count-storage', // localStorage 中的键名
    }
  )
);

略微完善一下以后

javascript 复制代码
// src/store/authStore.ts
import { create } from 'zustand';
import { persist, createJSONStorage } from 'zustand/middleware';

interface User {
  id: number;
  name: string;
  email: string;
  // 可以添加更多用户属性
}

interface AuthState {
  token: string | null;
  user: User | null;
  isAuthenticated: boolean;
  login: (token: string, user: User) => void;
  logout: () => void;
  updateUserData: (userData: Partial<User>) => void;
  clearAuth: () => void;
}

// 创建 authStore
export const useAuthStore = create<AuthState>()(
  persist(
    (set) => ({
      // 初始状态
      token: null,
      user: null,
      isAuthenticated: false,
      
      // 登录函数
      login: (token, user) => {
        set({
          token,
          user,
          isAuthenticated: true,
        });
      },
      
      // 退出登录函数
      logout: () => {
        set({
          token: null,
          user: null,
          isAuthenticated: false,
        });
      },
      
      // 更新用户数据函数
      updateUserData: (userData) => {
        set((state) => ({
          user: state.user ? { ...state.user, ...userData } : null,
        }));
      },
      
      // 清除认证状态函数
      clearAuth: () => {
        set({
          token: null,
          user: null,
          isAuthenticated: false,
        });
      },
    }),
    {
      name: 'AdminToken', // localStorage 中的键名
      storage: createJSONStorage(() => localStorage),
      partialize: (state) => ({
        token: state.token,
        user: state.user,
        isAuthenticated: state.isAuthenticated,
      }),
      // 可选:自定义版本控制,当 store 结构发生变化时使用
      version: 1,
    }
  )
);

再次测试,即便我们刷新,存储在本地的数据也不会丢失

3、项目使用

接下来在我们的项目之中进行使用

使用起来也非常的简单,可以拆分API的方式,也可以API直接组合的方式进行使用

javascript 复制代码
import { useAuthStore } from '@/store/authStore';


const { login} = useAuthStore();
login(res.token, res.user);

不得不说,太简单便捷了

相关推荐
进击的尘埃24 分钟前
前端大文件上传全方案:切片、秒传、断点续传与 Worker 并行 Hash 计算实践
javascript
aykon24 分钟前
DataSource详解以及优势
前端
Mintopia24 分钟前
戴了 30 天智能手环后,我才发现自己一直低估了“睡眠”
前端
leolee1824 分钟前
react redux 简单使用
前端·react.js·redux
仰望星空的小猴子26 分钟前
常用的Hooks
前端
天才熊猫君26 分钟前
Vue Fragment 锚点机制
前端
米丘27 分钟前
Git 常用操作命令
前端
西梯卧客27 分钟前
[1-2] 数据类型检测 · typeof、instanceof、toString.call 等方式对比
javascript
星_离29 分钟前
SSE—实时信息推送
前端
wuhen_n1 小时前
响应式探秘:ref vs reactive,我该选谁?
前端·javascript·vue.js