ReactJS组件中显示的视频未更新
Video displayed in ReactJS component not updating
我是ReactJS(0.13.1)的新手,我在应用程序中创建了一个显示HTML5视频的组件。
它看起来很完美,但只适用于第一次选择。当您从一个视频切换到另一个视频时(当this.props.video
发生变化时),页面中实际显示和播放的视频不会发生变化。
我可以在Chrome检查器中看到<source src='blah.mp4' />
元素的更新,但页面中实际渲染的视频不会改变,并且会继续播放(如果已经播放的话)。Safari&Firefox。所有其他元素也相应地更新。
有什么想法吗?
不管怎样,我下面的组件:
(function(){
var React = require('react');
var VideoView = React.createClass({
render: function(){
var video = this.props.video;
var title = video.title === ''? video.id : video.title;
var sourceNodes = video.media.map(function(media){
media = 'content/'+media;
return ( <source src={media} /> )
});
var downloadNodes = video.media.map(function(media){
var ext = media.split('.').slice(-1)[0].toUpperCase();
media = 'content/'+media;
return (<li><a className="greybutton" href={media}>{ext}</a></li>)
});
return (
<div className="video-container">
<video title={title} controls width="100%">
{sourceNodes}
</video>
<h3 className="video-title">{title}</h3>
<p>{video.description}</p>
<div className="linkbox">
<span>Downloads:</span>
<ul className="downloadlinks">
{downloadNodes}
</ul>
</div>
</div>
)
}
});
module.exports = VideoView;
})();
更新:
用另一种方式描述:
我有一个带有onClick处理程序的链接列表,这些处理程序设置了组件的道具。
当我第一次点击视频链接("video Foo")时,我得到了
<video title="Video Foo" controls>
<source src="video-foo.mp4"/>
<source src="video-foo.ogv"/>
</video>
并且"Video Foo"出现并且可以播放。
然后,当我点击下一个("视频栏")时,DOM会更新,我会得到
<video title="Video Bar" controls>
<source src="video-bar.mp4"/>
<source src="video-bar.ogv"/>
</video>
然而,它仍然是"视频Foo"是可见的,可以播放。
这就像浏览器加载了<video>
的媒体后,会忽略对<source>
元素的任何更改。
我在这里描述了一些纯JavaScript的方法。基于此,我为React找到了适合我的解决方案:
-
在视频本身上使用
src
属性:var Video = React.createComponent({ render() { return <video src={this.props.videoUrl} />; } });
Dana的回答是扩展此解决方案的一个很好的选择。
-
在视频元素上使用
.load()
调用var Video = React.createComponent({ componentDidUpdate(_prevProps, _prevState) { React.findDOMNode(this.refs.video).load(); // you can add logic to check if sources have been changed }, render() { return ( <video ref="video"> {this.props.sources.map(function (srcUrl, index) { return <source key={index} src={srcUrl} />; })} </video> ); } });
UPD:
-
当然,可以为
<video>
标记添加唯一的key
属性(例如,基于您的源),所以当源发生更改时,它也会发生更改。但这将导致<video>
被完全重新渲染,并可能导致一些UI闪烁。var Video = React.createComponent({ render() { return ( <video key={this.props.videoId}> {this.props.sources.map(function (srcUrl, index) { return <source key={index} src={srcUrl} />; })} </video> ); } });
我遇到了同样的问题,我无法访问<video>
HTML标记,因为我正在使用一个库来渲染视频(而不是本地<video>
HTML标记),该库在内部负责渲染<video>
标记。
在这种情况下,我找到了另一种解决方案,我认为解决同样的问题更好。
之前:
<VideoLibrary src={this.props.src} />
之后:
<React.Fragment key={this.props.src}>
<VideoLibrary src={this.props.src} />
</React.Fragment>
如果您使用的是本机<video>
HTML标记:
<React.Fragment key={this.props.src}>
<video src={this.props.src} />
</React.Fragment>
这种方式React将呈现不同的视频标签,因为src
道具将不同,因此每次都会呈现不同的HTML标签以避免此问题。
我发现这种方法更干净、更简单,如果您有权或没有权访问<video>
HTML标记,则在这两种情况下都可以使用。
找到答案
当源元素已经插入到视频或音频元素中时,动态修改该元素及其属性将不会产生任何效果。要更改正在播放的内容,只需直接使用media元素上的src属性,可以使用canPlayType()方法从可用资源中进行选择。通常,在文档解析后手动操作源元素是一种不必要的复杂方法
https://html.spec.whatwg.org/multipage/embedded-content.html#the-源元素
这是一个相当粗糙和脆弱的,但它完成了我的案件。
(function(){
var React = require('react');
var VideoView = React.createClass({
pickSource: function(media){
var vid = document.createElement('video');
var maybes = media.filter(function(media){
var ext = media.split('.').slice(-1)[0].toUpperCase();
return (vid.canPlayType('video/'+ext) === 'maybe');
});
var probablies = media.filter(function(media){
var ext = media.split('.').slice(-1)[0].toUpperCase();
return (vid.canPlayType('video/'+ext) === 'probably');
});
var source = '';
if (maybes.length > 0) { source = maybes[0]; }
if (probablies.length > 0) { source = probablies[0]; }
source = (source === '')? '' : 'content/'+source;
return source;
},
render: function(){
var video = this.props.video;
var title = video.title === ''? video.id : video.title;
var src = this.pickSource(video.media);
var downloadNodes = video.media.map(function(media){
var ext = media.split('.').slice(-1)[0].toUpperCase();
media = 'content/'+media;
return (
<li><a className="greybutton" href={media}>{ext}</a></li>
)
});
return (
<div className="video-container">
<video title={title} src={src} controls width="100%"></video>
<h3 className="video-title">{title}</h3>
<p>{video.description}</p>
<div className="linkbox">
<span>Downloads:</span>
<ul className="downloadlinks">
{downloadNodes}
</ul>
</div>
</div>
)
}
});
module.exports = VideoView;
})();
尝试这种方式
import React, { Component } from "react";
class Video extends Component<any, any> {
video: any = React.createRef();
componentDidUpdate(preProps: any) {
const { url } = this.props;
if (preProps && preProps.url && url) {
if (preProps.url !== url) {
this.video.current.src = url;
}
}
}
render() {
const { url } = this.props;
return (
<video controls ref={this.video}>
<source src={url} type="video/mp4" />
Your browser does not support HTML5 video.
</video>
);
}
}
多亏了这家伙的博客,我的类似问题只需在视频标签中添加一个关键属性就解决了。
<video key={displayItem.key} controls>
<source src={`${Config.MEDIA_URL}${displayItem.awsfile}`} />
</video>
公认的答案可能已经过时了?
我在制作视频播放列表时也遇到了同样的问题。
所以我将视频播放器分离到另一个react组件并且该组件接收到两个道具:contentId(视频标识)&videoUrl(视频URL)。
此外,我在视频标签中添加了一个ref,这样我就可以管理标签了。
var Video = React.createClass({
componentWillReceiveProps (nextProps) {
if (nextProps.contentId != this.props.contentId) {
this.refs['videoPlayer'].firstChild.src = this.props.videoUrl;
this.refs['videoPlayer'].load()
}
},
propType: {
contentId: React.PropTypes.string, // this is the id of the video so you can see if they equal, if not render the component with the new url
videoUrl: React.PropTypes.string, // the video url
} ,
getDefaultProps(){
return {
};
},
render() {
return (
<video ref="videoPlayer" id="video" width="752" height="423">
<source src={this.props.videoUrl} type="video/mp4" />
</video>
);
}
});
module.exports = Video;
这要干净得多:
<Video contentId="12" videoUrl="VIDEO_URL" />
尝试删除源标签,而只使用视频标签并添加src属性,如以下示例
<video src={video} className="lazy" loop autoPlay muted playsInline poster="" />
如果您正在从服务器获取数据,并且希望它在您有新数据后更新视频链接。
import React, {Fragment, useEffect, useState} from "react";
const ChangeVID =(props)=> {
const [prevUploaded, setPrevUploaded] =useState(null);
useEffect(()=>{
if(props.changeIMG) {
setPrevUploaded(props.changeIMG)}
},[])
return(<Fragment>
{prevUploaded && <Suspense
fallback={<div>loading</div>}>
<div className="py-2" >
{ <video id={prevUploaded.duration} width="320" height="240" controls >
<source src={prevUploaded.url} type="video/mp4" />
</video>}
</div>
</Suspense>
}<);
}
- 如何检查用户在html5视频播放器中观看了完整的视频
- 输入字段将't获取更新的值
- 在javascript中添加和显示对象的随机数组中的视频
- 如何解析Brightcove视频中的视频缩略图
- 如何创建包含多个视频的视频横幅
- 如何检查Json文件更新,如果更新了,则用更新的数据刷新我的页面
- 如何使用angularjs在iframe中嵌入来自数据库的视频链接
- 使我的视频标头响应
- Javascript的视频音量问题
- 我可以设置HTML5文件上传的视频长度限制吗
- 如何将缩略图链接到新页面上的视频
- 使用SeleniumWebdriver(带有Java)测试没有ID的视频
- AudioContext从blob获取数据的视频创建MediaElementSource
- 如何让iPhone用户在我的网站上观看带字幕的视频
- 如何修改此功能以获得最受欢迎的视频?(YouTube API v3)
- setAttribute和video.src用于更改IE9中不起作用的视频标记源
- ReactJS组件中显示的视频未更新
- 如何创建独立于数组更新的组件列表
- YouTube嵌入的视频在动态更新iframe-src时停止播放
- 我更新了相同的视频ID,但youtube-api v3仍然显示“视频未找到”