ReactJS无法更改视频和海报视频

时间:2014-10-08 11:02:45

标签: reactjs video.js

我想在选择视频更改后更改视频海报和源VideoJS

var VideoPlayer = React.createClass({
  render: function() {
    var selectedVideo = this.props.selectedVideo;
    function filterVideo(video) {
      return video.id == selectedVideo;
    }

    var data = this.props.videos.filter(filterVideo);
    return (
      <div className="col-md-6 videoplayer">
        <h2>{data[0].title}</h2>
        <video id="videoplayer" className="video-js vjs-default-skin vjs-big-play-centered" controls preload="none"
          width="100%"
          height="300"
          poster={data[0].poster}
          data-setup="{}">
          <source src={data[0].video} type='video/mp4' />
        </video>
        <div className="video-description">
          {data[0].description}
        </div>
      </div>
    );
  }
});

但我收到了错误:

Uncaught Error: Invariant Violation: ReactMount: Two valid but unequal nodes with the same `data-reactid`: .0.0.1.1 

标题和说明已更改,但视频海报未更改

5 个答案:

答案 0 :(得分:16)

这是破坏性库的问题。基本上会发生什么是渲染<video>元素,然后VideoJS在<video>旁边注入一堆兄弟元素(子元素很好)。

React尝试更新元素,它无法弄清楚发生了什么,所以它会发生恐慌并发出错误。

所以你有两个选择:

选项1:渲染<div ref="target" />,在componentDidMount和this.refs.target.appendChild(that)中构建视频节点,然后手动调用VideoJS。在componentWillRecieveProps中,您需要直接更新海报img的src。

选项2:fork video.js并使其仅发出事件而不是直接修改DOM。您的组件将对这些事件做出反应,修改状态,并呈现海报,按钮等。

选项1更容易,选项2可能更高效,更清洁。我会选择选项1.


这些都不是好的解决方案,但是逃离容器的库不能很好地发挥作用。

答案 1 :(得分:11)

如果有人需要FakeRainBrigand的答案示例,这就是我的视频课最终看起来的样子。

Video = React.createClass({
  componentDidMount: function() {
    var video, wrapper;
    wrapper = document.createElement('div');
    wrapper.innerHTML = "<video id='attachmentVideo' class='video-js vjs-default-skin' controls preload='auto' width='640' height='264' poster='" + this.props.thumbnail + "'><source src='" + this.props.url + "' type='video/mp4' /><p className='vjs-no-js'>To view this video please enable JavaScript, and consider upgrading to a web browser that <a href='http://videojs.com/html5-video-support/' target='_blank'>supports HTML5 video</a></p></video>";
    video = wrapper.firstChild;
    this.refs.target.getDOMNode().appendChild(video);
    return videojs(video, {});
  },
  render: function() {
    return (
      <div id="attachmentViewer">
        <h2>{this.props.title}</h2>
        <div id="attachmentVideoContainer" ref="target" />
      </div>
    );
  }
});

答案 2 :(得分:0)

不是100%相关,但如果你正在寻找一个更“纯粹”的反应解决方案来实现videoJS作为一个组件,这就是我做的......

最后一篇文章是前一段时间,我不知道是否有人想出更好的实现,但是,我做的是以下内容:

  1. 将videojs函数添加为getInitialState prop,并为getInitialState添加了“videoHTML”道具。
  2. 在componentDidMount方法中生成我的视频标记和来源,并将该变量字符串分配给videoHTML状态道具。
  3. 在componentWillUnmount()方法中添加了实例化的vjs播放器的dispose()和初始状态的replaceState。
  4. 添加了一个组件函数__initVideo(elem),它检查传入的元素是否有子元素,如果是,则“this.vjsPlayer = this.state.initVideoJS(elem.children [0],{})”。然后我返回this.vjsPlayer。
  5. 在render()方法的附件div中,我将dangerouslySetInnerHTML prop设置为this.state.videoHTML prop,并设置一个调用__initVideo函数的ref,传入div。
  6. 无法发布任何代码,但这与我已经能够理解的视频JS的纯React实现非常接近。

答案 3 :(得分:0)

  
    

1.import

  
     

从“ react-dom”导入ReactDOM

     
    

2.inside函数

  

this.setstate({vidio:“ {新网址作为来源}”“)var name = ReactDOM.findDOMNode(this.video)name.src = this.state.video.url

  
    

3.Template

  
     

this.video =视频} src = {this.state.video.url}                          />

答案 4 :(得分:0)

有一个question可以回答这个问题(我认为这应该适用于您的情况,否则请告诉我)。您可以通过检查播放器是否发生变化,然后像下面这样更改src,将其从jQuery中的示例更改为React代码。

componentDidUpdate(prevProps) {
    if (prevProps.src !== this.props.src) { //see if the src changes
        if (this.initialized) { //check if the player has been previously initialized
            this.player.src({ //set the players new source
                src: this.props.src,
                type: 'video/mp4'
            })
        } else { 
            this.attemptInitialization() //only initialize player if it hasn't been
        }
    }
}