ReactJS не может менять видео и постеры
Я хочу изменить видео постер и источник 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
название и описание изменены, но видео постер не меняется
3 ответа
Это проблема с деструктивными библиотеками. В основном, что происходит, вы делаете <video>
элемент, а затем VideoJS вставляет кучу элементов одного уровня рядом с вашим <video>
(дочерние элементы в порядке).
React пытается обновить элемент, и он не может понять, что происходит, поэтому он паникует и выдает эту ошибку.
Итак, у вас есть два варианта:
Вариант 1: сделать <div ref="target" />
создайте видео узел в componentDidMount и this.refs.target.appendChild(that)
, а затем вызвать VideoJS вручную. В componentWillRecieveProps вам необходимо напрямую обновить src автора img.
Вариант 2: распакуйте video.js и сделайте так, чтобы он генерировал только события вместо прямой модификации DOM. Ваш компонент будет реагировать на эти события, изменяя состояние и отображая плакат, кнопки и т. Д.
Вариант 1 проще, вариант 2 потенциально более эффективен и чище. Я бы пошел с вариантом 1.
Ни одно из этих решений не является хорошим решением, но библиотеки, которые покидают свой контейнер, не очень хорошо реагируют на реакцию.
В случае, если кому-то нужен пример ответа от 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>
);
}
});
Есть вопрос, который отвечает на этот вопрос (я думаю, это должно сработать в вашем случае, дайте мне знать иначе). Вы можете изменить его на код React из их примера, который находится в jQuery, проверив, изменился ли игрок, а затем изменив src следующим образом:
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
}
}
}
1. импорт
import ReactDOM from 'react-dom'
2. внутренняя функция
this.setstate({vidio:"{new url as a source}") var name = ReactDOM.findDOMNode(this.video) name.src=this.state.video.url
3. шаблон
<VideoPlayer ref={video => this.video = video}src={this.state.video.url}
/>
Не на 100%, но если вы ищете более "чистое" решение для реагирования на реализацию videoJS как компонента, это то, что я сделал...
Последнее сообщение было некоторое время назад, и я не знаю, придумал ли кто-нибудь лучшую реализацию, однако, я сделал следующее:
- Добавил функцию videojs как реквизит getInitialState и также добавил реквизит "videoHTML" в getInitialState.
- Сгенерировал мой видео тег и источники в методе componentDidMount и назначил эту переменную строку для свойства videoHTML.
- В метод componentWillUnmount () добавлен dispose () созданного экземпляра проигрывателя vjs и replaceState из начального состояния.
- Добавлена функция компонента __initVideo(elem), которая проверяет, есть ли у переданного элемента дочерние элементы, и если это так, то "this.vjsPlayer = this.state.initVideoJS(elem.children[0], {})". Затем я возвращаю this.vjsPlayer.
- В div вложения в методе render() я установил опору dangerouslySetInnerHTML в реквизит this.state.videoHTML и установил ссылку, которая вызывает функцию __initVideo, передавая в div.
Не могу опубликовать какой-либо код, но это настолько близко к чистой реализации React videoJS, что я смог выяснить.