ReactJS 组件中显示的视频未更新
Posted
技术标签:
【中文标题】ReactJS 组件中显示的视频未更新【英文标题】:Video displayed in ReactJS component not updating 【发布时间】:2015-05-31 06:00:17 【问题描述】:我是 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 >
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>
但它仍然是可见且可以播放的“Video Foo”。
就像一旦浏览器加载了<video>
的媒体,它就会忽略对<source>
元素的任何更改。
【问题讨论】:
type 是可选的,如果没有提供类型,浏览器会向提供文件的服务器查询。 【参考方案1】:我已经描述了一些纯 javascript here 的方法。基于此,我找到了适合我的 React 解决方案:
在视频本身上使用src
属性:
var Video = React.createComponent(
render()
return <video src=this.props.videoUrl />;
);
Dana's answer 是扩展此解决方案的绝佳选择。
使用.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>
);
);
【讨论】:
【参考方案2】:找到答案
当元素已插入视频或音频元素时,动态修改源元素及其属性将无效。要更改正在播放的内容,只需直接使用媒体元素上的 src 属性,可能使用 canPlayType() 方法从可用资源中进行选择。通常,在文档解析后手动操作源元素是一种不必要的复杂方法
https://html.spec.whatwg.org/multipage/embedded-content.html#the-source-element
这是一个相当老套和脆弱的,但它为我的案例完成了工作。
(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 ></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;
)();
【讨论】:
【参考方案3】:我遇到了同样的问题,我无法访问 <video>
HTML 标记,因为我正在使用一个库来呈现视频(不是本机 <video>
HTML 标记),它在内部负责呈现 @ 987654323@标签。
在这种情况下,我找到了另一种解决方案,我认为它可以更好地解决相同的问题。
之前:
<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 标记,都可以在这两种情况下使用。
【讨论】:
这对我们有用!【参考方案4】:试试这个方法
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>
);
【讨论】:
【参考方案5】:我在制作包含视频的播放列表时遇到了同样的问题。
所以我将视频播放器分离到另一个反应组件 并且该组件收到了两个道具:contentId(视频标识)和 videoUrl(视频 URL)。
我还为视频标签添加了一个引用,以便我可以管理标签。
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" >
<source src=this.props.videoUrl type="video/mp4" />
</video>
);
);
module.exports = Video;
这更干净:
<Video contentId="12" videoUrl="VIDEO_URL" />
【讨论】:
【参考方案6】:尝试删除源标签,而只保留视频标签并像这个例子一样添加 src 属性
<video src=video className="lazy" loop autoPlay muted playsInline poster="" />
【讨论】:
【参考方案7】:如果您从服务器获取数据,并且希望它在获得新数据后更新视频链接。
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 controls >
<source src=prevUploaded.url type="video/mp4" />
</video>
</div>
</Suspense>
<);
【讨论】:
以上是关于ReactJS 组件中显示的视频未更新的主要内容,如果未能解决你的问题,请参考以下文章