使用setTimeout设置hover状态时所有React电影卡片状态异常问题
问题核心原因
- 事件绑定写法错误:
onMouseEnter需要接收函数作为回调,你直接传入setTimeout(...)会在组件渲染阶段就立即执行定时逻辑,返回的定时器ID被当成事件回调,所有卡片初始化时就会排队触发展开,才会出现所有卡片状态同时修改的问题。 - 缺少定时器清理机制:如果用户悬停不满1秒就移走鼠标,定时器不会被中断,仍然会在1秒后触发对应卡片展开,不符合交互需求。
修正后代码
import { useState, useRef, useEffect } from 'react'; import ReactPlayer from 'react-player'; // 图标组件导入按你原有逻辑保留即可 function RowPoster({ movie, isTrending }) { const [isHovered, setIsHovered] = useState(false); // 用ref存储定时器ID,避免组件重渲染导致引用丢失 const hoverTimerRef = useRef(null); const trailerUrl = movie.trailer_url; // 组件卸载时清除残留定时器,避免内存泄漏 useEffect(() => { return () => { if (hoverTimerRef.current) clearTimeout(hoverTimerRef.current); }; }, []); return ( <div className={`RowPoster ${isTrending && "isTrending"}`} onMouseEnter={() => { // 先清理残留定时器,避免重复触发 if (hoverTimerRef.current) clearTimeout(hoverTimerRef.current); hoverTimerRef.current = setTimeout(() => setIsHovered(true), 1000); }} onMouseLeave={() => { // 鼠标移走先清定时器,悬停不满1秒不会触发展开 if (hoverTimerRef.current) clearTimeout(hoverTimerRef.current); setIsHovered(false); }} > <img src={movie.cover_image} alt={movie.titles.en} /> {isHovered && ( <> <ReactPlayer className="video" width="100%" height="160px" loop={true} playing={false} url={trailerUrl} /> <div className="item__info"> <h4>{movie.titles.en}</h4> <div className="icons"> <PlayArrow className="icon" /> <Add /> <ThumbUpAltOutlined className="icon" /> <ThumbDownOutlined className="icon" /> <KeyboardArrowDown className="icon" /> </div> <div className="stats"> <span className="stats_score">{`Score ${movie.score}%`}</span> </div> <div className="genre"> <ul className="genre_items"> {movie.genres.map((genre, idx) => ( <li key={idx}>{genre}</li> ))} </ul> </div> </div> </> )} </div> ); } export default RowPoster;
修改说明
- 给
onMouseEnter的定时逻辑套了一层回调函数,只有鼠标真正进入卡片时才会启动定时器,不会在组件渲染阶段就自动执行 - 新增多处定时器清理逻辑,彻底避免误触发和内存泄漏问题
- 优化了分类项渲染逻辑,改用map遍历避免硬编码索引可能出现的报错
内容的提问来源于stack exchange,提问作者Bradley Juma
相关产品推荐
相关产品推荐

