如何实现定时重渲染组件的队列?解决游戏头部轮播展示问题
问题分析与修复方案
现存问题点
- 变量名混乱:代码中混用
name和nameFirstBlood状态,导致逻辑执行错乱,比如调用setNameFirstBlood但状态定义是name。 - 定时器叠加冲突:每次用户加入触发
useEffect时都会创建新定时器,旧定时器未彻底清理,多个定时器同时执行导致名字切换速度异常。 - 首个用户展示延迟:后续用户加入时,旧定时器干扰了首个用户的展示流程,本该立即展示的内容被延迟。
- 超时恢复逻辑错误:每个用户单独设置恢复定时器,未考虑多用户轮播完成后再统一触发2分钟超时恢复。
修复后的实现代码
import { useState, useEffect, useRef } from 'react'; const [header, setHeader] = useState(headerLogo); // 统一状态命名,包含用户数组和当前展示索引 const [leaderboard, setLeaderboard] = useState({ users: [], currentIndex: 0 }); // 用ref存储定时器ID,跨useEffect清理 const carouselTimerRef = useRef(null); const resetTimerRef = useRef(null); // WebSocket消息监听:新增答对用户 useEffect(() => { if (!webSocket.current) return; const handleMessage = (event) => { if (event.data.startsWith('{')) { const rawData = event.data.replaceAll(`'`, `"`); const data = JSON.parse(rawData); setLeaderboard(prev => { // 避免重复添加同一用户(可根据业务调整判断条件) const isExist = prev.users.some(user => user.name === data.name); if (isExist) return prev; return { ...prev, users: [...prev.users, { name: data.name, score: data.score }], currentIndex: 0 // 新用户加入时重置展示顺序 }; }); } }; webSocket.current.onmessage = handleMessage; return () => { webSocket.current.onmessage = null; }; }, []); // 仅绑定一次监听,避免重复触发 // 头部轮播与超时恢复逻辑 useEffect(() => { // 清理旧定时器 if (carouselTimerRef.current) clearTimeout(carouselTimerRef.current); if (resetTimerRef.current) clearTimeout(resetTimerRef.current); const { users, currentIndex } = leaderboard; const USER_DISPLAY_DURATION = 10000; // 单个用户展示10秒 const TOTAL_RESET_DURATION = 120000; // 无新用户时2分钟恢复原标题 if (users.length === 0) { setHeader(headerLogo); return; } // 立即展示当前索引的用户 const currentUser = users[currentIndex]; setHeader( <Header name={currentUser.name} score={currentUser.score} /> ); // 多用户轮播:非最后一个用户,10秒后切换下一个 if (currentIndex < users.length - 1) { carouselTimerRef.current = setTimeout(() => { setLeaderboard(prev => ({ ...prev, currentIndex: prev.currentIndex + 1 })); }, USER_DISPLAY_DURATION); } else { // 最后一个用户展示完后,启动恢复定时器 resetTimerRef.current = setTimeout(() => { setHeader(headerLogo); setLeaderboard({ users: [], currentIndex: 0 }); // 清空状态 }, TOTAL_RESET_DURATION); } // 组件卸载或状态变化时清理定时器 return () => { clearTimeout(carouselTimerRef.current); clearTimeout(resetTimerRef.current); }; }, [leaderboard, headerLogo]); // localStorage同步逻辑(按需求保留) useEffect(() => { localStorage.setItem('leaderboard', JSON.stringify(leaderboard)); }, [leaderboard]); useEffect(() => { const saved = localStorage.getItem('leaderboard'); if (saved) { setLeaderboard(JSON.parse(saved)); } }, []);
关键改动说明
- 统一状态管理:用
leaderboard状态整合用户数组和展示索引,避免变量名混淆。 - 定时器Ref存储:确保每次状态变化时彻底清理旧定时器,解决叠加冲突问题。
- 即时展示首个用户:数组有用户时立即展示当前内容,修复首个用户延迟问题。
- 轮播+超时逻辑分离:多用户时按10秒间隔轮播,最后一个用户展示完后启动2分钟恢复定时器;新用户加入自动重置轮播流程。
- WebSocket监听优化:仅绑定一次消息监听,避免重复触发导致的异常。
内容的提问来源于stack exchange,提问作者tadS
相关产品推荐
相关产品推荐

