// src/hooks/useFollowingEvents.js // 关注事件管理自定义 Hook(与 Redux 状态同步,支持多组件共用) import { useState, useCallback, useEffect, useRef } from 'react'; import { useSelector, useDispatch } from 'react-redux'; import { useToast } from '@chakra-ui/react'; import { logger } from '../utils/logger'; import { loadFollowingEvents as loadFollowingEventsAction, toggleFollowEvent } from '../store/slices/stockSlice'; const EVENTS_PAGE_SIZE = 8; /** * 关注事件管理 Hook(导航栏专用) * 提供关注事件加载、分页、取消关注等功能 * 监听 Redux 中的 followingEvents 变化,自动同步 * * @returns {{ * followingEvents: Array, * eventsLoading: boolean, * eventsPage: number, * setEventsPage: Function, * EVENTS_PAGE_SIZE: number, * loadFollowingEvents: Function, * handleUnfollowEvent: Function * }} */ export const useFollowingEvents = () => { const toast = useToast(); const dispatch = useDispatch(); const [eventsPage, setEventsPage] = useState(1); // 从 Redux 获取关注事件数据(与 GlobalSidebar 共用) const followingEvents = useSelector(state => state.stock.followingEvents || []); const eventsLoading = useSelector(state => state.stock.loading?.followingEvents || false); // 从 Redux 获取关注事件列表长度(用于监听变化) const reduxEventsLength = useSelector(state => state.stock.followingEvents?.length || 0); // 用于跟踪上一次的事件长度 const prevEventsLengthRef = useRef(-1); // 初始化时加载 Redux followingEvents(确保 Redux 状态被初始化) const hasInitializedRef = useRef(false); useEffect(() => { if (!hasInitializedRef.current) { hasInitializedRef.current = true; logger.debug('useFollowingEvents', '初始化 Redux followingEvents'); dispatch(loadFollowingEventsAction()); } }, [dispatch]); // 加载关注事件(通过 Redux) const loadFollowingEvents = useCallback(() => { logger.debug('useFollowingEvents', '触发 loadFollowingEvents'); dispatch(loadFollowingEventsAction()); }, [dispatch]); // 监听 Redux followingEvents 长度变化,自动更新分页 useEffect(() => { const currentLength = reduxEventsLength; const prevLength = prevEventsLengthRef.current; // 当事件列表长度变化时,更新分页(确保不超出范围) if (prevLength !== -1 && currentLength !== prevLength) { const newMaxPage = Math.max(1, Math.ceil(currentLength / EVENTS_PAGE_SIZE)); setEventsPage(p => Math.min(p, newMaxPage)); } prevEventsLengthRef.current = currentLength; }, [reduxEventsLength]); // 取消关注事件(通过 Redux) const handleUnfollowEvent = useCallback(async (eventId) => { try { // 通过 Redux action 取消关注(乐观更新) await dispatch(toggleFollowEvent({ eventId, isFollowing: true // 表示当前已关注,需要取消 })).unwrap(); toast({ title: '已取消关注该事件', status: 'info', duration: 1500 }); } catch (e) { logger.error('useFollowingEvents', '取消关注事件失败', e); toast({ title: e.message || '操作失败', status: 'error', duration: 2000 }); // 失败时重新加载列表 dispatch(loadFollowingEventsAction()); } }, [dispatch, toast]); return { followingEvents, eventsLoading, eventsPage, setEventsPage, EVENTS_PAGE_SIZE, loadFollowingEvents, handleUnfollowEvent }; };