crush-level-web/src/hooks/useRedDot.md

227 lines
5.4 KiB
Markdown
Raw Normal View History

2025-11-13 08:38:25 +00:00
# useRedDot Hook 使用指南
## 概述
`useRedDot` 是一个用于管理应用中红点提示的 React Hook。它提供了完整的红点状态管理功能**默认显示红点,查看后消失**。
## 特性
-**默认显示逻辑**localStorage 不存在记录时显示红点
-**自动持久化**:使用 localStorage 存储已查看状态
-**一次性显示**:查看后自动消失
-**命名空间隔离**:通过前缀避免键名冲突
-**批量操作**:支持批量标记已读和清除
-**TypeScript 支持**:完整的类型定义
## 基本用法
### 1. 导入 Hook
```typescript
import { useRedDot, RED_DOT_KEYS } from '@/hooks/useRedDot';
```
### 2. 在组件中使用
```typescript
const MyComponent = () => {
const { hasRedDot, markAsViewed, showRedDot } = useRedDot({
prefix: 'my_feature_' // 可选,默认为 'red_dot_'
});
return (
<div>
<div className="flex items-center gap-2">
<span>设置</span>
{hasRedDot('settings') && <Badge variant="dot" />}
</div>
<button onClick={() => markAsViewed('settings')}>
查看设置
</button>
</div>
);
};
```
## API 参考
### 参数
```typescript
interface UseRedDotOptions {
prefix?: string; // localStorage 键名前缀,默认 'red_dot_'
}
```
### 返回值
```typescript
interface UseRedDotReturn {
// 检查是否显示红点
hasRedDot: (key: string) => boolean;
// 标记为已查看(消除红点)
markAsViewed: (key: string) => void;
// 显示红点
showRedDot: (key: string) => void;
// 批量标记已查看
markMultipleAsViewed: (keys: string[]) => void;
// 清除所有红点
clearAllRedDots: () => void;
// 获取所有有红点的功能键
getAllRedDotKeys: () => string[];
}
```
## 预定义常量
为了避免硬编码字符串,提供了预定义的红点键:
```typescript
export const RED_DOT_KEYS = {
CHAT_BUBBLE: 'chat_bubble',
CHAT_BACKGROUND: 'chat_background',
CHAT_MODEL: 'chat_model',
PROFILE_SETTING: 'profile_setting',
} as const;
```
## 完整示例
### 聊天设置页面
```typescript
import { useRedDot, RED_DOT_KEYS } from '@/hooks/useRedDot';
import { Badge } from '@/components/ui/badge';
const ChatSettingsPage = () => {
const { hasRedDot, markAsViewed } = useRedDot({
prefix: `chat_${chatId}_`
});
const handleBubbleSettingClick = () => {
// 点击时标记为已查看
markAsViewed(RED_DOT_KEYS.CHAT_BUBBLE);
// 打开设置页面
openBubbleSettings();
};
return (
<div>
<div className="setting-item" onClick={handleBubbleSettingClick}>
<div className="flex items-center gap-2">
<span>聊天气泡</span>
{hasRedDot(RED_DOT_KEYS.CHAT_BUBBLE) && <Badge variant="dot" />}
</div>
</div>
<div className="setting-item" onClick={() => {
markAsViewed(RED_DOT_KEYS.CHAT_BACKGROUND);
openBackgroundSettings();
}}>
<div className="flex items-center gap-2">
<span>聊天背景</span>
{hasRedDot(RED_DOT_KEYS.CHAT_BACKGROUND) && <Badge variant="dot" />}
</div>
</div>
</div>
);
};
```
### 管理页面(显示红点)
```typescript
const AdminPage = () => {
const { showRedDot } = useRedDot();
const handleNewFeatureRelease = () => {
// 发布新功能时显示红点
showRedDot(RED_DOT_KEYS.CHAT_BUBBLE);
showRedDot(RED_DOT_KEYS.CHAT_BACKGROUND);
};
return (
<button onClick={handleNewFeatureRelease}>
发布聊天新功能
</button>
);
};
```
## 高级用法
### 1. 不同用户/场景的隔离
```typescript
// 为不同用户使用不同前缀
const userARedDot = useRedDot({ prefix: `user_${userA.id}_` });
const userBRedDot = useRedDot({ prefix: `user_${userB.id}_` });
// 为不同功能模块使用不同前缀
const chatRedDot = useRedDot({ prefix: 'chat_' });
const profileRedDot = useRedDot({ prefix: 'profile_' });
```
### 2. 批量操作
```typescript
const { markMultipleAsViewed, clearAllRedDots } = useRedDot();
// 用户查看了整个设置页面,标记多个功能为已读
const handleSettingsPageVisit = () => {
markMultipleAsViewed([
RED_DOT_KEYS.CHAT_BUBBLE,
RED_DOT_KEYS.CHAT_BACKGROUND,
RED_DOT_KEYS.CHAT_MODEL
]);
};
// 重置所有红点(比如用户重新登录)
const handleUserLogin = () => {
clearAllRedDots();
};
```
### 3. 状态监控
```typescript
const { getAllRedDotKeys, hasRedDot } = useRedDot();
// 获取当前所有未读功能
const unreadFeatures = getAllRedDotKeys();
console.log('用户有', unreadFeatures.length, '个未读功能');
// 检查是否有任何未读
const hasAnyUnread = unreadFeatures.length > 0;
```
## 注意事项
1. **localStorage 限制**:确保浏览器支持 localStorage
2. **前缀命名**:使用有意义的前缀避免冲突
3. **性能考虑**:避免在 render 方法中频繁调用 showRedDot
4. **错误处理**Hook 内部已处理 localStorage 异常
## 存储格式
红点状态在 localStorage 中的存储格式:
```
键名: ${prefix}${redDotKey}
值: 'viewed' | undefined (删除)
```
**重要逻辑**
- **不存在记录** = 显示红点(默认状态)
- **存在 'viewed' 记录** = 不显示红点(已查看)
例如:
- 无记录 -> 显示红点
- `chat_123_chat_bubble: 'viewed'` -> 不显示红点
- `profile_settings: 'viewed'` -> 不显示红点