如何处理react-player结合autoplay使用时的播放/暂停状态问题
问题根因
- 浏览器自动播放策略默认禁止无用户交互的音频/视频自动播放,你初始化设置
playing=true的请求会被浏览器静默拦截,此时本地playing状态为true,但播放器实际未播放,出现状态和实际播放行为不同步的问题 - 你直接通过修改
playing状态控制播放的逻辑没有校验浏览器是否真的允许播放,同时原有代码没有给ReactPlayer绑定ref,无法读取到正确的播放器实例状态,才会出现点击一次按钮状态不更新、需要点击两次的问题
解决方案
ReactPlayer本身提供了实例播放/暂停方法和状态同步回调,不需要完全依赖本地state硬控制播放,调整逻辑如下:
- 给ReactPlayer绑定ref,直接调用实例的
play()、pause()方法触发播放暂停,不受本地state缓存值的影响 - 用ReactPlayer提供的
onPlay、onPause回调同步本地playing状态,保证状态永远和播放器实际行为一致,避免不同步问题
调整后代码示例
import { useRef, useState } from 'react'; import ReactPlayer from 'react-player'; import IconButton from '@mui/material/IconButton'; import PlayArrowIcon from '@mui/icons-material/PlayArrow'; import PauseIcon from '@mui/icons-material/Pause'; export default function Untitled() { const playerRef = useRef(null); // 初始可以设为false,自动播放成功后通过回调自动更新为true const [playing, setPlaying] = useState(false) const handlePlayClick = async () => { try { // 直接调用实例播放方法,返回promise,播放成功才会resolve await playerRef.current.play(); } catch (err) { // 播放被拦截的情况可以在这里加提示逻辑 console.log('播放失败', err); } } const handlePauseClick = () => { playerRef.current.pause(); } return ( <div> <ReactPlayer ref={playerRef} // 补充绑定ref style={{display:"none"}} controls={false} playing={playing} wrapper={"audio"} progressInterval={200} // 播放成功触发回调,同步状态 onPlay={() => setPlaying(true)} // 暂停成功触发回调,同步状态 onPause={() => setPlaying(false)} config={{ file: { attributes: {preload: "auto"}, forceAudio:true, }, }} /> <IconButton size="small"> {playing ? ( <PauseIcon onClick={handlePauseClick}/> ) : ( <PlayArrowIcon onClick={handlePlayClick}/> )} </IconButton> </div> ) }
额外说明
- 如果需要尝试自动播放,可以在组件挂载后调用
playerRef.current.play(),被浏览器拦截的话会进入catch逻辑,不会影响后续手动点击播放的逻辑 - 不用手动维护状态做
false改true再改回false的重置操作,直接调用实例方法会自动处理播放器内部状态
内容的提问来源于stack exchange,提问作者GooMee
相关产品推荐
相关产品推荐

