将 setTimeout 函数与设置特定状态的箭头函数一起使用时出现问题
Problem with using setTimeout function together with an arrow function that sets a particular state
我正在尝试复制当您将鼠标悬停在 Netflix 上的特定电影图块上时,电影图块会在一段时间后展开以显示更多信息的情况。
目前,我已成功扩展磁贴以显示有关悬停的更多信息,但设置超时以便仅在鼠标悬停超过 1000 毫秒后才显示信息,这证明会产生不需要的结果。
到目前为止,我已经尝试过了,但问题是当我悬停时,所有其他电影图块的状态都发生了变化,而不仅仅是悬停的那个
function RowPoster({ movie, isTrending }) {
const [isHovered, setisHovered] = useState(false);
const trailerUrl = movie.trailer_url;
return (
<div
className={`RowPoster ${isTrending && "isTrending"}`}
onMouseEnter={setTimeout(() => setisHovered(true), 1000)}
onMouseLeave={() => 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">
<li>{movie.genres[0]}</li>
<li>{movie.genres[1]}</li>
<li>{movie.genres[2]}</li>
<li>{movie.genres[3]}</li>
</ul>
</div>
</div>
</>
)}
</div>
);
}
export default RowPoster;
在您提供的代码中,渲染时调用了超时。因此,每个渲染的影片块的状态都会发生变化。要在触发事件时调用 setTimeout,您需要将其包装在一个函数中:
...
onMouseEnter={() => setTimeout(() => setisHovered(true), 1000)}
...
对于“鼠标悬停超过 1000 毫秒后显示信息”的行为,您需要更多代码:
function RowPoster({ movie, isTrending }) {
const [isHovered, setisHovered] = useState(false);
const trailerUrl = movie.trailer_url;
const hoverTimerRef = useRef();
const handleCancelHover = useCallback(() => {
if (hoverTimerRef.current) {
clearTimeout(hoverTimerRef.current);
}
}, []);
const handleMouseEnter = useCallback(() => {
// save the timer id in the hoverTimerRef
hoverTimerRef.current = setTimeout(() => setisHovered(true), 1000);
}, []);
const handleMouseLeave = useCallback(() => {
// cancel the scheduled hover if the mouseLeave event is fired before the timer is triggered
handleCancelHover();
setisHovered(false);
}, [handleCancelHover]);
useEffect(() => {
return () => {
// cancel the scheduled hover when unmounting the component
handleCancelHover();
};
}, [handleCancelHover]);
return (
<div
className={`RowPoster ${isTrending && "isTrending"}`}
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
>
...
我正在尝试复制当您将鼠标悬停在 Netflix 上的特定电影图块上时,电影图块会在一段时间后展开以显示更多信息的情况。
目前,我已成功扩展磁贴以显示有关悬停的更多信息,但设置超时以便仅在鼠标悬停超过 1000 毫秒后才显示信息,这证明会产生不需要的结果。
到目前为止,我已经尝试过了,但问题是当我悬停时,所有其他电影图块的状态都发生了变化,而不仅仅是悬停的那个
function RowPoster({ movie, isTrending }) {
const [isHovered, setisHovered] = useState(false);
const trailerUrl = movie.trailer_url;
return (
<div
className={`RowPoster ${isTrending && "isTrending"}`}
onMouseEnter={setTimeout(() => setisHovered(true), 1000)}
onMouseLeave={() => 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">
<li>{movie.genres[0]}</li>
<li>{movie.genres[1]}</li>
<li>{movie.genres[2]}</li>
<li>{movie.genres[3]}</li>
</ul>
</div>
</div>
</>
)}
</div>
);
}
export default RowPoster;
在您提供的代码中,渲染时调用了超时。因此,每个渲染的影片块的状态都会发生变化。要在触发事件时调用 setTimeout,您需要将其包装在一个函数中:
...
onMouseEnter={() => setTimeout(() => setisHovered(true), 1000)}
...
对于“鼠标悬停超过 1000 毫秒后显示信息”的行为,您需要更多代码:
function RowPoster({ movie, isTrending }) {
const [isHovered, setisHovered] = useState(false);
const trailerUrl = movie.trailer_url;
const hoverTimerRef = useRef();
const handleCancelHover = useCallback(() => {
if (hoverTimerRef.current) {
clearTimeout(hoverTimerRef.current);
}
}, []);
const handleMouseEnter = useCallback(() => {
// save the timer id in the hoverTimerRef
hoverTimerRef.current = setTimeout(() => setisHovered(true), 1000);
}, []);
const handleMouseLeave = useCallback(() => {
// cancel the scheduled hover if the mouseLeave event is fired before the timer is triggered
handleCancelHover();
setisHovered(false);
}, [handleCancelHover]);
useEffect(() => {
return () => {
// cancel the scheduled hover when unmounting the component
handleCancelHover();
};
}, [handleCancelHover]);
return (
<div
className={`RowPoster ${isTrending && "isTrending"}`}
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
>
...