SAAS/README-hooks.md
2025-05-14 00:30:11 +08:00

6.9 KiB
Raw Blame History

SaaS项目自定义钩子使用文档

简介

本文档介绍了SaaS项目中的自定义React钩子(Custom Hooks),这些钩子封装了常用的状态管理逻辑,使组件代码更加简洁、可读和可维护。

目录结构

src/
├── hooks/
│   ├── index.ts         # 统一导出所有钩子
│   ├── useUser.ts       # 用户相关钩子
│   └── useSettings.ts   # 设置相关钩子
└── store/
    ├── userStore.ts     # 用户状态管理
    └── settingStore.ts  # 设置状态管理

安装和导入

钩子已集成到项目中无需额外安装。使用时只需从hooks目录导入

// 导入单个钩子
import { useTheme } from '@/hooks';

// 或导入多个钩子
import { useTheme, useAuth, useUserProfile } from '@/hooks';

用户相关钩子

useUserInfo

获取当前登录用户的基本信息。

import { useUserInfo } from '@/hooks';

function UserInfoComponent() {
  const userInfo = useUserInfo();
  
  return (
    <div>
      <p>用户名: {userInfo?.username}</p>
      <p>邮箱: {userInfo?.email}</p>
    </div>
  );
}

useUserProfile

获取格式化后的用户信息适用于UI显示。

import { useUserProfile } from '@/hooks';

function ProfileComponent() {
  const profile = useUserProfile();
  
  return (
    <div>
      <p>用户名: {profile.username}</p>
      <p>邮箱: {profile.email}</p>
      <p>电话: {profile.phone}</p>
      <p>角色: {profile.roleName}</p>
    </div>
  );
}

useIsAdmin

检查当前用户是否为管理员。

import { useIsAdmin } from '@/hooks';

function AdminSection() {
  const isAdmin = useIsAdmin();
  
  if (!isAdmin) {
    return <p>您没有访问此页面的权限</p>;
  }
  
  return <div>管理员面板内容</div>;
}

useHasRole

检查当前用户是否拥有特定角色。

import { useHasRole } from '@/hooks';

function RoleBasedComponent() {
  const hasRole = useHasRole();
  
  return (
    <div>
      {hasRole('editor') && <button>编辑内容</button>}
      {hasRole('admin') && <button>管理设置</button>}
    </div>
  );
}

useAuth

管理用户登录状态和认证操作。

import { useAuth } from '@/hooks';

function LoginComponent() {
  const { isAuthenticated, login, logout } = useAuth();
  
  const handleLogin = async () => {
    const response = await fetch('/api/login', { /* 登录请求 */ });
    const data = await response.json();
    
    if (data.success) {
      login(data.token, data.user);
    }
  };
  
  return (
    <div>
      {isAuthenticated ? (
        <button onClick={logout}>退出登录</button>
      ) : (
        <button onClick={handleLogin}>登录</button>
      )}
    </div>
  );
}

设置相关钩子

useTheme

管理主题模式(亮色/暗色)和相关操作。

import { useTheme } from '@/hooks';

function ThemeToggleComponent() {
  const { 
    themeMode,
    isDarkMode, 
    toggleThemeMode, 
    enableLightMode, 
    enableDarkMode 
  } = useTheme();
  
  return (
    <div>
      <p>当前主题: {themeMode}</p>
      <button onClick={toggleThemeMode}>
        切换至{isDarkMode ? '亮色' : '暗色'}主题
      </button>
      <button onClick={enableLightMode} disabled={!isDarkMode}>
        切换至亮色主题
      </button>
      <button onClick={enableDarkMode} disabled={isDarkMode}>
        切换至暗色主题
      </button>
    </div>
  );
}

useApplyTheme

自动将当前主题应用到DOM。适用于自定义布局组件或页面。

import { useApplyTheme } from '@/hooks';

function Layout({ children }) {
  // 将当前主题应用到DOM
  useApplyTheme();
  
  return (
    <div className="layout">
      {children}
    </div>
  );
}

useSettings

获取所有系统设置。

import { useSettings } from '@/hooks';

function SettingsComponent() {
  const settings = useSettings();
  
  return (
    <div>
      <p>主题模式: {settings.themeMode}</p>
      {/* 其他设置项 */}
    </div>
  );
}

实际使用示例

下面是一个综合使用多个钩子的组件示例:

import { 
  useTheme, 
  useApplyTheme, 
  useUserProfile, 
  useIsAdmin, 
  useAuth 
} from '@/hooks';

function DashboardPage() {
  // 应用主题到DOM
  useApplyTheme();
  
  // 获取主题状态和操作
  const { isDarkMode, toggleThemeMode } = useTheme();
  
  // 获取用户信息和权限
  const userProfile = useUserProfile();
  const isAdmin = useIsAdmin();
  const { isAuthenticated, logout } = useAuth();
  
  if (!isAuthenticated) {
    return <LoginRedirect />;
  }
  
  return (
    <div className="dashboard">
      <header>
        <div className="user-info">
          <p>欢迎, {userProfile.username}</p>
          <button onClick={logout}>退出登录</button>
        </div>
        <button onClick={toggleThemeMode}>
          切换至{isDarkMode ? '亮色' : '暗色'}主题
        </button>
      </header>
      
      <main>
        {/* 普通用户内容 */}
        <UserContent />
        
        {/* 仅管理员可见内容 */}
        {isAdmin && <AdminPanel />}
      </main>
    </div>
  );
}

测试页面

项目中包含一个专门的测试页面,用于演示各种钩子的使用方法:

  • 路径: /test/usehook
  • 源代码: src/app/test/usehook/page.tsx

在这个页面上可以测试以下功能:

  • 主题切换
  • 用户登录/登出
  • 角色权限检查
  • 用户信息显示

最佳实践

  1. 避免重复导入基础store使用自定义钩子而不是直接导入store减少对底层实现的依赖。

  2. 优先使用语义化钩子:例如使用useIsAdmin()而不是useUserInfo().roleType === 'admin'

  3. 组合使用多个钩子:根据需要组合使用不同的钩子,构建复杂功能。

  4. 使用useMemo和useCallback:在性能敏感的场景中,确保不会导致不必要的重新渲染。

扩展自定义钩子

如需扩展现有钩子或添加新钩子,请遵循以下步骤:

  1. 在适当的文件中添加新钩子(useUser.tsuseSettings.ts
  2. hooks/index.ts中导出新钩子
  3. 确保包含适当的注释和类型定义
  4. 遵循三级注释规范(文件头注释、模块级注释、关键代码行注释)

常见问题

Q: 为什么推荐使用自定义钩子而不是直接使用store?

A: 自定义钩子提供了更高级别的抽象,隐藏了状态管理的复杂性,使组件代码更加简洁和易于维护。同时,它们可以更轻松地进行单元测试。

Q: 如何处理钩子之间的依赖关系?

A: 当一个钩子需要依赖另一个钩子时,应在钩子内部导入并使用依赖的钩子,而不是在组件中手动管理这些依赖关系。

Q: 如何确保钩子在正确的上下文中使用?

A: React钩子只能在React函数组件或其他自定义钩子中使用。确保不在类组件、普通函数或条件语句中直接调用钩子。