React Video组件点击后控制台打印play为false的生命周期疑问
问题根因
你的现象由React state异步更新特性、useEffect清理函数逻辑错误、缺少播放结束监听三个问题共同导致:
- React的state更新是异步批量处理的,调用
setPlay(true)后,当前作用域内的play变量仍然是本次渲染的旧值,需要等组件完成重渲染后才会拿到更新后的state。你在点击回调内和setPlay同作用域打印play,拿到的永远是点击前的状态,所以输出false。 - useEffect的清理函数会在每次依赖项变化、下一轮effect执行前触发,你在清理函数中写了
setPlay(false),相当于你刚把play改为true触发effect前,状态就被清理函数重置为false,逻辑完全错误。 - 你没有绑定video的
ended事件,视频播放结束后不会触发状态变更,永远不会打印预期的结束状态false。
修正后代码
const Video = ({src, type, index, isAutoPlay}) => { const [play, setPlay] = useState(isAutoPlay) const playRef = useRef(); // 状态变更后再执行播放/暂停逻辑和打印 useEffect(() => { if (!playRef.current) return if (play) { playRef.current.play(); console.log(true) } else { playRef.current.pause(); console.log(false) } }, [play]); // 监听播放结束事件修改状态 const handleEnded = () => setPlay(false) return ( <> <video className="slide" ref={playRef} onClick={() => setPlay(true)} onEnded={handleEnded}> <source src={src} type={type} key={index}/> Your browser does not support the video tag. </video> </> ) }
修正说明
- 将状态打印逻辑移到useEffect中,保证只有state真的更新完成后才打印,拿到的永远是最新值
- 删除了useEffect中错误的清理函数,避免状态被意外重置
- 新增
onEnded事件监听,视频播放完成后自动更新状态触发false打印 - 补充了暂停逻辑,后续如果需要实现点击切换播放/暂停,直接将点击回调改为
setPlay(prev => !prev)即可
内容的提问来源于stack exchange,提问作者Amâncio de Noronha Brito
相关产品推荐
相关产品推荐

