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);

不得不说,太简单便捷了

相关推荐
布列瑟农的星空9 分钟前
大话设计模式——关注点分离原则下的事件处理
前端·后端·架构
山有木兮木有枝_12 分钟前
node文章生成器
javascript·node.js
yvvvy28 分钟前
前端必懂的 Cache 缓存机制详解
前端
北海几经夏43 分钟前
React自定义Hook
前端·react.js
龙在天1 小时前
从代码到屏幕,浏览器渲染网页做了什么❓
前端
TimelessHaze1 小时前
【performance面试考点】让面试官眼前一亮的performance性能优化
前端·性能优化·trae
yes or ok1 小时前
前端工程师面试题-vue
前端·javascript·vue.js
我要成为前端高手1 小时前
给不支持摇树的三方库(phaser) tree-shake?
前端·javascript
Noxi_lumors2 小时前
VITE BALABALA require balabla not supported
前端·vite
周胜22 小时前
node-sass
前端