312 lines
6.9 KiB
Markdown
312 lines
6.9 KiB
Markdown
# 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函数组件或其他自定义钩子中使用。确保不在类组件、普通函数或条件语句中直接调用钩子。 |