feat: 实现 Socket 触发的智能列表自动刷新功能(带防抖)
核心改动: - 扩展 NotificationContext,添加事件更新回调注册机制 - VirtualizedFourRowGrid 添加 forwardRef 暴露 getScrollPosition 方法 - DynamicNewsCard 实现智能刷新逻辑(根据模式和滚动位置判断是否刷新) - Community 页面注册 Socket 回调自动触发刷新 - 创建 TypeScript 通用防抖工具函数(debounce.ts) - 集成防抖机制(2秒延迟),避免短时间内频繁请求 智能刷新策略: - 纵向模式 + 第1页:自动刷新列表 - 纵向模式 + 其他页:不刷新(避免打断用户) - 平铺模式 + 滚动在顶部:自动刷新列表 - 平铺模式 + 滚动不在顶部:仅显示 Toast 提示 防抖效果: - 短时间内收到多个新事件,只执行最后一次刷新 - 减少服务器压力,提升用户体验 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
// src/views/Community/index.js
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { useNavigate, useLocation } from 'react-router-dom';
|
||||
import { useSelector, useDispatch } from 'react-redux';
|
||||
import {
|
||||
fetchPopularKeywords,
|
||||
@@ -40,6 +40,7 @@ import { PROFESSIONAL_COLORS } from '../../constants/professionalTheme';
|
||||
|
||||
const Community = () => {
|
||||
const navigate = useNavigate();
|
||||
const location = useLocation(); // ⚡ 获取当前路由信息(用于判断是否在 /community 页面)
|
||||
const dispatch = useDispatch();
|
||||
|
||||
// Redux状态
|
||||
@@ -71,7 +72,10 @@ const Community = () => {
|
||||
});
|
||||
|
||||
// ⚡ 通知权限引导
|
||||
const { browserPermission, requestBrowserPermission } = useNotification();
|
||||
const { browserPermission, requestBrowserPermission, registerEventUpdateCallback } = useNotification();
|
||||
|
||||
// ⚡ DynamicNewsCard 的 ref(用于触发刷新)
|
||||
const dynamicNewsCardRef = useRef(null);
|
||||
|
||||
// 通知横幅显示状态
|
||||
const [showNotificationBanner, setShowNotificationBanner] = useState(false);
|
||||
@@ -160,6 +164,63 @@ const Community = () => {
|
||||
return () => clearTimeout(timer);
|
||||
}, []); // 空依赖数组,只在组件挂载时执行一次
|
||||
|
||||
/**
|
||||
* ⚡ 【核心逻辑】注册 Socket 新事件回调 - 当收到新事件时智能刷新列表
|
||||
*
|
||||
* 工作流程:
|
||||
* 1. Socket 收到 'new_event' 事件 → NotificationContext 触发所有注册的回调
|
||||
* 2. 本回调被触发 → 检查当前路由是否为 /community
|
||||
* 3. 如果在 /community 页面 → 调用 DynamicNewsCard.refresh() 方法
|
||||
* 4. DynamicNewsCard 根据模式和滚动位置决定是否刷新:
|
||||
* - 纵向模式 + 第1页 → 刷新列表
|
||||
* - 纵向模式 + 其他页 → 不刷新(避免打断用户)
|
||||
* - 平铺模式 + 滚动在顶部 → 刷新列表
|
||||
* - 平铺模式 + 滚动不在顶部 → 仅显示 Toast 提示
|
||||
*
|
||||
* 设计要点:
|
||||
* - 使用 registerEventUpdateCallback 注册回调,返回的函数用于清理
|
||||
* - 路由检查:只在 /community 页面触发刷新
|
||||
* - 智能刷新:由 DynamicNewsCard 根据上下文决定刷新策略
|
||||
* - 自动清理:组件卸载时自动注销回调
|
||||
*/
|
||||
useEffect(() => {
|
||||
// 定义回调函数
|
||||
const handleNewEvent = (eventData) => {
|
||||
console.log('[Community] 🔔 收到新事件通知', {
|
||||
currentPath: location.pathname,
|
||||
eventData,
|
||||
});
|
||||
|
||||
// 检查是否在 /community 页面
|
||||
if (location.pathname === '/community') {
|
||||
console.log('[Community] ✅ 当前在事件中心页面,触发 DynamicNewsCard 刷新');
|
||||
|
||||
// 调用 DynamicNewsCard 的 refresh 方法(智能刷新)
|
||||
if (dynamicNewsCardRef.current) {
|
||||
dynamicNewsCardRef.current.refresh();
|
||||
} else {
|
||||
console.warn('[Community] ⚠️ DynamicNewsCard ref 不可用,无法触发刷新');
|
||||
}
|
||||
} else {
|
||||
console.log('[Community] ⏭️ 当前不在事件中心页面,跳过刷新', {
|
||||
currentPath: location.pathname,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 注册回调(返回清理函数)
|
||||
const unregister = registerEventUpdateCallback(handleNewEvent);
|
||||
console.log('[Community] ✅ 已注册 Socket 事件更新回调');
|
||||
|
||||
// 组件卸载时清理
|
||||
return () => {
|
||||
if (unregister) {
|
||||
unregister();
|
||||
console.log('[Community] 🧹 已注销 Socket 事件更新回调');
|
||||
}
|
||||
};
|
||||
}, [location.pathname, registerEventUpdateCallback]); // 依赖路由变化重新注册
|
||||
|
||||
return (
|
||||
<Box minH="100vh" bg={bgColor}>
|
||||
{/* 主内容区域 */}
|
||||
@@ -206,6 +267,7 @@ const Community = () => {
|
||||
|
||||
{/* 实时要闻·动态追踪 - 横向滚动 */}
|
||||
<DynamicNewsCard
|
||||
ref={dynamicNewsCardRef} // ⚡ 传递 ref(用于触发刷新)
|
||||
filters={filters}
|
||||
popularKeywords={popularKeywords}
|
||||
lastUpdateTime={lastUpdateTime}
|
||||
|
||||
Reference in New Issue
Block a user