React使用map渲染react-player时点击按钮播放全部而非选中视频的问题
问题原因
- 全局共用同一个
isPlaying状态,所有ReactPlayer的playing属性都绑定了该值,状态变更会触发所有视频同步播放/暂停 - 循环复用单个
useRef实例,后续赋值会覆盖之前的引用,最终ref仅指向数组最后一个视频
解决方案
把全局播放状态改为存储「当前正在播放的视频索引」,同时用数组类型的ref存储所有视频的实例引用,点击时仅操作对应索引的状态和ref即可。
修改后完整代码
import React, {useState, useRef} from 'react'; import {useStaticQuery, graphql} from 'gatsby'; import ReactPlayer from 'react-player'; import {Button} from '../Buttons/Button'; import './videos.scss'; import '../../Molecules/Cards/cards.scss'; const VideoCards = () => { const { allVideoCardsJson } = useStaticQuery( graphql` query VideoQuery { allVideoCardsJson { edges { node { title source } } } } `) // 存储当前播放的视频索引,null代表无播放视频 const [playingIndex, setPlayingIndex] = useState(null); // 用数组存储所有视频的ref实例 const videoRefs = useRef([]); const togglePlay = (index) => { // 点击当前正在播放的视频,执行暂停 if (playingIndex === index) { setPlayingIndex(null); videoRefs.current[index]?.getInternalPlayer().pauseVideo(); return; } // 先暂停之前正在播放的视频 if (playingIndex !== null) { videoRefs.current[playingIndex]?.getInternalPlayer().pauseVideo(); } // 播放当前选中的视频 setPlayingIndex(index); videoRefs.current[index]?.getInternalPlayer().playVideo(); } return ( <div className="card-container__videos"> {allVideoCardsJson.edges.map(({node, index}) => ( <div className="video-card" key={index}> <ReactPlayer ref={el => videoRefs.current[index] = el} url={node.source} width="100%" pip={true} controls={true} playing={playingIndex === index} ></ReactPlayer> <Button onClick={() => togglePlay(index)} style={{zIndex:'200'}} label="Play Video"></Button> </div> ))} </div> ); }; export default VideoCards;
注意说明
代码中使用?.可选链运算符是为了避免ref未完成挂载时调用方法报错,如果你的项目环境不支持该语法,可以替换为&&判断写法:videoRefs.current[index] && videoRefs.current[index].getInternalPlayer().pauseVideo()
内容的提问来源于stack exchange,提问作者Nikki Peel
相关产品推荐
相关产品推荐

