React中如何每秒更新视频播放进度条?
视频进度条优化:解决setTimeout导致的重复渲染问题
我在做视频播放进度条时,用setTimeout调用setTime更新状态来刷新组件,但这个方案明显不太行。加了console.log后发现组件每次会渲染2-4次,代码如下:
const ProgressBar = ({ player }) => { const [time, setTime] = useState(0); let dur = player.getDuration() || 3600; console.log(Math.floor(time)); setTimeout(() => { setTime(player.getCurrentTime()); }, 1000); return ( <Progress value={(time * 100) / dur} size="xs" bg="white" minW="100vw" /> ); };
问题出在哪?
每次组件渲染都会创建新的setTimeout,状态更新后又触发新一轮渲染,循环下来就会出现多次渲染,还可能留下内存泄漏的隐患。
优化方案
1. 用useEffect管控定时器
把定时器放到useEffect里,依赖项设为player,确保只在组件挂载或player变化时创建定时器,同时在组件卸载或依赖变化时清理定时器:
const ProgressBar = ({ player }) => { const [time, setTime] = useState(0); const dur = player.getDuration() || 3600; useEffect(() => { // 用setInterval替代setTimeout,持续更新进度 const timer = setInterval(() => { setTime(player.getCurrentTime()); }, 1000); // 清理函数:组件卸载或player变化时清除定时器 return () => clearInterval(timer); }, [player]); return ( <Progress value={(time * 100) / dur} size="xs" bg="white" minW="100vw" /> ); };
2. 监听视频原生事件(最优解)
比起定时轮询,直接监听视频的timeupdate事件更高效——只有当视频播放时间真的变化时才更新状态,完全避免无意义的渲染:
const ProgressBar = ({ player }) => { const [time, setTime] = useState(0); const dur = player.getDuration() || 3600; useEffect(() => { const updateTime = () => { setTime(player.getCurrentTime()); }; // 绑定timeupdate事件 player.addEventListener('timeupdate', updateTime); // 组件卸载时移除事件监听 return () => { player.removeEventListener('timeupdate', updateTime); }; }, [player]); return ( <Progress value={(time * 100) / dur} size="xs" bg="white" minW="100vw" /> ); };
timeupdate事件由浏览器自动触发,频率适配视频播放状态,比定时轮询精准且性能更好。
3. 额外优化:减少无关渲染
- 用
React.memo包裹组件,避免父组件无关更新导致的重复渲染:const ProgressBar = React.memo(({ player }) => { // 内部代码不变 }); - 用
useMemo缓存时长计算结果,避免每次渲染重复计算:const dur = useMemo(() => player.getDuration() || 3600, [player]);
内容的提问来源于stack exchange,提问作者Mustafa
相关产品推荐
相关产品推荐

