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

5.4 KiB
Raw Blame History

useRedDot Hook 使用指南

概述

useRedDot 是一个用于管理应用中红点提示的 React Hook。它提供了完整的红点状态管理功能默认显示红点,查看后消失

特性

  • 默认显示逻辑localStorage 不存在记录时显示红点
  • 自动持久化:使用 localStorage 存储已查看状态
  • 一次性显示:查看后自动消失
  • 命名空间隔离:通过前缀避免键名冲突
  • 批量操作:支持批量标记已读和清除
  • TypeScript 支持:完整的类型定义

基本用法

1. 导入 Hook

import { useRedDot, RED_DOT_KEYS } from '@/hooks/useRedDot';

2. 在组件中使用

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 参考

参数

interface UseRedDotOptions {
  prefix?: string; // localStorage 键名前缀,默认 'red_dot_'
}

返回值

interface UseRedDotReturn {
  // 检查是否显示红点
  hasRedDot: (key: string) => boolean;
  
  // 标记为已查看(消除红点)
  markAsViewed: (key: string) => void;
  
  // 显示红点
  showRedDot: (key: string) => void;
  
  // 批量标记已查看
  markMultipleAsViewed: (keys: string[]) => void;
  
  // 清除所有红点
  clearAllRedDots: () => void;
  
  // 获取所有有红点的功能键
  getAllRedDotKeys: () => string[];
}

预定义常量

为了避免硬编码字符串,提供了预定义的红点键:

export const RED_DOT_KEYS = {
  CHAT_BUBBLE: 'chat_bubble',
  CHAT_BACKGROUND: 'chat_background',
  CHAT_MODEL: 'chat_model',
  PROFILE_SETTING: 'profile_setting',
} as const;

完整示例

聊天设置页面

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>
  );
};

管理页面(显示红点)

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. 不同用户/场景的隔离

// 为不同用户使用不同前缀
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. 批量操作

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. 状态监控

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' -> 不显示红点