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

312 lines
6.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# SaaS项目自定义钩子使用文档
## 简介
本文档介绍了SaaS项目中的自定义React钩子(Custom Hooks),这些钩子封装了常用的状态管理逻辑,使组件代码更加简洁、可读和可维护。
## 目录结构
```
src/
├── hooks/
│ ├── index.ts # 统一导出所有钩子
│ ├── useUser.ts # 用户相关钩子
│ └── useSettings.ts # 设置相关钩子
└── store/
├── userStore.ts # 用户状态管理
└── settingStore.ts # 设置状态管理
```
## 安装和导入
钩子已集成到项目中无需额外安装。使用时只需从hooks目录导入
```tsx
// 导入单个钩子
import { useTheme } from '@/hooks';
// 或导入多个钩子
import { useTheme, useAuth, useUserProfile } from '@/hooks';
```
## 用户相关钩子
### useUserInfo
获取当前登录用户的基本信息。
```tsx
import { useUserInfo } from '@/hooks';
function UserInfoComponent() {
const userInfo = useUserInfo();
return (
<div>
<p>用户名: {userInfo?.username}</p>
<p>邮箱: {userInfo?.email}</p>
</div>
);
}
```
### useUserProfile
获取格式化后的用户信息适用于UI显示。
```tsx
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
检查当前用户是否为管理员。
```tsx
import { useIsAdmin } from '@/hooks';
function AdminSection() {
const isAdmin = useIsAdmin();
if (!isAdmin) {
return <p>您没有访问此页面的权限</p>;
}
return <div>管理员面板内容</div>;
}
```
### useHasRole
检查当前用户是否拥有特定角色。
```tsx
import { useHasRole } from '@/hooks';
function RoleBasedComponent() {
const hasRole = useHasRole();
return (
<div>
{hasRole('editor') && <button>编辑内容</button>}
{hasRole('admin') && <button>管理设置</button>}
</div>
);
}
```
### useAuth
管理用户登录状态和认证操作。
```tsx
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
管理主题模式(亮色/暗色)和相关操作。
```tsx
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。适用于自定义布局组件或页面。
```tsx
import { useApplyTheme } from '@/hooks';
function Layout({ children }) {
// 将当前主题应用到DOM
useApplyTheme();
return (
<div className="layout">
{children}
</div>
);
}
```
### useSettings
获取所有系统设置。
```tsx
import { useSettings } from '@/hooks';
function SettingsComponent() {
const settings = useSettings();
return (
<div>
<p>主题模式: {settings.themeMode}</p>
{/* 其他设置项 */}
</div>
);
}
```
## 实际使用示例
下面是一个综合使用多个钩子的组件示例:
```tsx
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.ts``useSettings.ts`
2.`hooks/index.ts`中导出新钩子
3. 确保包含适当的注释和类型定义
4. 遵循三级注释规范(文件头注释、模块级注释、关键代码行注释)
## 常见问题
**Q: 为什么推荐使用自定义钩子而不是直接使用store?**
A: 自定义钩子提供了更高级别的抽象,隐藏了状态管理的复杂性,使组件代码更加简洁和易于维护。同时,它们可以更轻松地进行单元测试。
**Q: 如何处理钩子之间的依赖关系?**
A: 当一个钩子需要依赖另一个钩子时,应在钩子内部导入并使用依赖的钩子,而不是在组件中手动管理这些依赖关系。
**Q: 如何确保钩子在正确的上下文中使用?**
A: React钩子只能在React函数组件或其他自定义钩子中使用。确保不在类组件、普通函数或条件语句中直接调用钩子。