2018 年 10 月更新
根据这篇文章,我了解到 React 目前与领先的 WebRTC 服务提供商 100% 不兼容。到目前为止,我与两个 WebRTC 服务提供商合作过,它们都需要 dom 元素的 ID,并将视频流附加到它,而不是通过 React,而是通过直接 dom 操作。在 React 渲染中,这些流会间歇性地从完成的渲染中丢失。
它间歇性的原因是因为存在竞争条件。React 将运行渲染函数,并且您的 WebRTC 代码独立地订阅视频流并尝试将其附加到渲染创建的元素。如果订阅尝试将视频流附加到元素,则在渲染函数创建它之前,完成的渲染中缺少流。
根据同一篇文章,解决方案是通过 dom 操作插入所有与 WebRTC 相关的 dom 元素,从而将 React 与 WebRTC 完全分离,例如:
let elDialUIContainer = document.querySelector('#dialComponentUIContainer');
if (!elDialUIContainer) {
elDialUIContainer = document.createElement('div');
elDialUIContainer.setAttribute('id', 'dialComponentUIContainer');
elDialUIContainer.setAttribute('style', this.styleObjectToString(styles.dialComponentUIContainer));
elContentContainer.prepend(elDialUIContainer);
}
[.....]
if (localThis.applicationState.remoteVideoStream) {
console.log('attaching remoteVideoStream to #video' + localThis.applicationState.remoteVideoStream.getId());
let elOtherCallerVideoStream = document.querySelector('#video' + localThis.applicationState.remoteVideoStream.getId());
if (!elOtherCallerVideoStream) {
localThis.applicationState.remoteVideoStream.play('remoteCallerVideo');
}
}
...ETC。这些元素被添加到一个 dom 元素中,该元素位于该组件的 React 渲染函数生成的元素之上和之外——因此当该渲染函数运行时它们不会受到影响。
我有一个函数,addWebRTCElements
将这些元素添加到 dom。它由 调用ComponentDidMount()
,并且每次发生 WebRTC 事件时也会调用它,例如远程流进来。
过时:2018 年 9 月更新
这是另一种方法,使用 React createRef()
:
获取视频元素的 React 引用。在 React 组件构造函数中:
this.refToMyVideo = React.createRef();
将 html 元素附加到此 ref。在 React 渲染函数中:
<video ref={this.refToMyVideo}>
</video>
- 当视频流可用时使用 ref:
let vidElement = this.refToMyVideo.current;
attachMediaStream(vidElement, stream);
vidElement.onloadedmetadata = function(e) {
vidElement.play();
};
关于 React createRef 的文档在这里。
过时:从 2017 年 12 月开始:
@jordan,我认为您提出了一个很好的观点:“访问虚拟 dom 的方式不连续以及 attachMediaStream 的工作方式。”
这是我的处理方式。到目前为止,它似乎正在工作,尽管可能有一个更优雅的解决方案。
function attachMediaStreamToElement(idToWaitFor, stream){
const elementExists = $(idToWaitFor).length > 0;
if (elementExists) {
const idToWaitForMinusPoundSign = idToWaitFor.replace("#", "");
var vid = document.getElementById(idToWaitForMinusPoundSign);
attachMediaStream(vid, stream);
}
else {
setTimeout(function () {
attachMediaStreamToElement(idToWaitFor, idToWaitFor, stream)
}, 50);
}
}
一旦流可用,我就会调用它。该例程等待 Render 函数渲染目标元素,然后将流附加到它。