React状态更新时ReactPlayer组件className未同步更新问题
问题原因
外层包裹div是原生DOM元素,props变化会直接同步更新,而ReactPlayer是第三方封装组件,内部对播放核心逻辑之外的props做了浅比较优化:当key、url等核心props不变时,即使传入的className发生变化,组件不会主动更新DOM上的类名属性,导致样式不同步问题。
另外原代码还有两个隐藏bug:
- 类名拼接逻辑缺少空格分隔:
stylesWrapper中2个流的类名和3个流的类名拼接时没有留空格,会生成无效的连缀类名 - 业务逻辑说明单页最多支持4个播放器,但类名判断只覆盖了1/2/3个流的场景,漏了4个流的分支
修复方案
优先选择第一种方案,体验最好:
- 方案一:所有动态样式全部绑定到自主可控的外层原生div上,完全绕开第三方组件的props更新限制。不要给ReactPlayer传动态className,通过CSS父子选择器控制内部播放器的尺寸样式即可,不会触发播放器重新缓冲。
修正后的代码:
const ctx = useContext(ThemeContext); // 统一计算外层容器类名,补全4流分支,修复类名拼接问题 const wrapperClass = (() => { const streamCount = ctx.searchedStreams.length; switch (streamCount) { case 1: return classes.wrapperOneStream; case 2: return classes.wrapperTwoStreams; case 3: return classes.wrapperThreeStreams; case 4: return classes.wrapperFourStreams; default: return ""; } })(); return ( <> {ctx.searchedStreams.map((label) => ( <div className={wrapperClass} key={label}> <ReactPlayer url={`https://www.twitch.tv/${label}`} width="100%" height="100%" theme="dark" playing={true} /> </div> ))} </> );
后续写CSS时直接通过外层类名控制内部播放器样式即可,例:
.wrapperTwoStreams { width: 50%; height: 50%; } .wrapperTwoStreams video { object-fit: cover; }
- 方案二:如果必须给ReactPlayer传className,可以给组件绑定带流总数的key,强制类名变化时组件重挂载。但这个方案会导致每次增减播放器时,已加载的流全部重新缓冲,体验较差:
<ReactPlayer key={`${label}-${ctx.searchedStreams.length}`} className={stylesPlayer} url={`https://www.twitch.tv/${label}`} width="100%" theme="dark" playing={true} />

内容的提问来源于stack exchange,提问作者Garrett.a
相关产品推荐
相关产品推荐

