React Context变量在setInterval中不同步问题求解
这是React闭包陷阱导致的——定时器函数会捕获它创建时所在渲染周期的spotifyPlayer变量值,后续即使Context里的spotifyPlayer更新,定时器里拿到的还是最初的旧值,所以paused始终显示为true。
下面给两种可行的解决方法:
方法一:用useRef保存最新的播放器状态
用useRef存储最新的spotifyPlayer引用,让定时器能随时获取当前最新的播放状态:
import { useState, useEffect, useRef } from 'react'; import { useSpotifyContext } from './SpotifyContext'; function Player() { const spotifyPlayer = useSpotifyContext(); const [localPosition, setLocalPosition] = useState(0); // 用ref保存最新的播放器实例 const playerRef = useRef(spotifyPlayer); // 同步最新的播放器实例到ref,同时更新localPosition useEffect(() => { playerRef.current = spotifyPlayer; setLocalPosition(spotifyPlayer.playback.position); }, [spotifyPlayer]); useEffect(() => { const timer = setInterval(() => { // 从ref中获取最新的paused状态 if (!playerRef.current.playback.paused) { setLocalPosition(prev => prev + 1000); // 按实际精度调整递增数值,这里假设每秒+1000 } }, 1000); return () => clearInterval(timer); }, []); return ( <div> <p>当前播放位置:{localPosition}</p> </div> ); } export default Player;
方法二:将spotifyPlayer加入定时器useEffect的依赖数组
每次spotifyPlayer更新时,销毁旧定时器并创建新的,新定时器会自动捕获最新的paused值:
import { useState, useEffect } from 'react'; import { useSpotifyContext } from './SpotifyContext'; function Player() { const spotifyPlayer = useSpotifyContext(); const [localPosition, setLocalPosition] = useState(0); // 同步播放器的position到localPosition useEffect(() => { setLocalPosition(spotifyPlayer.playback.position); }, [spotifyPlayer]); useEffect(() => { const timer = setInterval(() => { if (!spotifyPlayer.playback.paused) { setLocalPosition(prev => prev + 1000); } }, 1000); return () => clearInterval(timer); }, [spotifyPlayer]); // 依赖加入spotifyPlayer,更新时重建定时器 return ( <div> <p>当前播放位置:{localPosition}</p> </div> ); } export default Player;
两种方法都能解决问题:方法一更高效,不会频繁销毁重建定时器;方法二更直观易理解。如果需要更精准的位置同步,可以把定时器间隔调小(比如100ms),同时对应调整递增的数值。
内容的提问来源于stack exchange,提问作者szym
相关产品推荐
相关产品推荐

