6.9 KiB
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
在这个页面上可以测试以下功能:
- 主题切换
- 用户登录/登出
- 角色权限检查
- 用户信息显示
最佳实践
-
避免重复导入基础store:使用自定义钩子而不是直接导入store,减少对底层实现的依赖。
-
优先使用语义化钩子:例如使用
useIsAdmin()
而不是useUserInfo().roleType === 'admin'
。 -
组合使用多个钩子:根据需要组合使用不同的钩子,构建复杂功能。
-
使用useMemo和useCallback:在性能敏感的场景中,确保不会导致不必要的重新渲染。
扩展自定义钩子
如需扩展现有钩子或添加新钩子,请遵循以下步骤:
- 在适当的文件中添加新钩子(
useUser.ts
或useSettings.ts
) - 在
hooks/index.ts
中导出新钩子 - 确保包含适当的注释和类型定义
- 遵循三级注释规范(文件头注释、模块级注释、关键代码行注释)
常见问题
Q: 为什么推荐使用自定义钩子而不是直接使用store?
A: 自定义钩子提供了更高级别的抽象,隐藏了状态管理的复杂性,使组件代码更加简洁和易于维护。同时,它们可以更轻松地进行单元测试。
Q: 如何处理钩子之间的依赖关系?
A: 当一个钩子需要依赖另一个钩子时,应在钩子内部导入并使用依赖的钩子,而不是在组件中手动管理这些依赖关系。
Q: 如何确保钩子在正确的上下文中使用?
A: React钩子只能在React函数组件或其他自定义钩子中使用。确保不在类组件、普通函数或条件语句中直接调用钩子。