2017-08-14 22:02:48 +01:00
|
|
|
# Video.js and ReactJS integration
|
2017-01-26 22:16:52 +01:00
|
|
|
|
2021-07-06 21:49:33 +02:00
|
|
|
Here are a couple ReactJS player implementations.
|
|
|
|
|
|
|
|
## React Functional Component and useEffect Example
|
|
|
|
|
|
|
|
```jsx
|
|
|
|
import React from "react";
|
|
|
|
import videojs from "video.js";
|
|
|
|
import "video.js/dist/video-js.css";
|
|
|
|
|
|
|
|
export const VideoJS = ( props ) => {
|
|
|
|
|
|
|
|
const videoRef = React.useRef(null);
|
2021-08-24 05:21:47 +08:00
|
|
|
const playerRef = React.useRef(null);
|
|
|
|
const { options, onReady } = props;
|
2021-07-06 21:49:33 +02:00
|
|
|
|
2021-08-24 05:21:47 +08:00
|
|
|
React.useEffect(() => {
|
|
|
|
// make sure Video.js player is only initialized once
|
|
|
|
if (!playerRef.current) {
|
|
|
|
const videoElement = videoRef.current;
|
|
|
|
if (!videoElement) return;
|
2021-07-06 21:49:33 +02:00
|
|
|
|
2021-08-24 05:21:47 +08:00
|
|
|
const player = playerRef.current = videojs(videoElement, options, () => {
|
2021-07-06 21:49:33 +02:00
|
|
|
console.log("player is ready");
|
2021-08-24 05:21:47 +08:00
|
|
|
onReady && onReady(player);
|
2021-07-06 21:49:33 +02:00
|
|
|
});
|
2021-08-24 05:21:47 +08:00
|
|
|
} else {
|
|
|
|
// you can update player here [update player through props]
|
|
|
|
// const player = playerRef.current;
|
|
|
|
// player.autoplay(options.autoplay);
|
|
|
|
// player.src(options.sources);
|
2021-07-06 21:49:33 +02:00
|
|
|
}
|
2021-11-10 14:03:39 -05:00
|
|
|
}, [options, videoRef]);
|
2021-08-24 05:21:47 +08:00
|
|
|
|
|
|
|
// Dispose the Video.js player when the functional component unmounts
|
|
|
|
React.useEffect(() => {
|
2021-11-10 14:03:39 -05:00
|
|
|
const player = playerRef.current;
|
|
|
|
|
2021-07-06 21:49:33 +02:00
|
|
|
return () => {
|
2021-11-10 14:03:39 -05:00
|
|
|
if (player) {
|
|
|
|
player.dispose();
|
2021-08-24 05:21:47 +08:00
|
|
|
playerRef.current = null;
|
2021-07-06 21:49:33 +02:00
|
|
|
}
|
2021-08-24 05:21:47 +08:00
|
|
|
};
|
2021-11-10 14:03:39 -05:00
|
|
|
}, [playerRef]);
|
2021-07-06 21:49:33 +02:00
|
|
|
|
2021-08-24 05:21:47 +08:00
|
|
|
return (
|
|
|
|
<div data-vjs-player>
|
|
|
|
<video ref={videoRef} className="video-js vjs-big-play-centered" />
|
|
|
|
</div>
|
|
|
|
);
|
2021-07-06 21:49:33 +02:00
|
|
|
}
|
|
|
|
|
2021-08-24 05:21:47 +08:00
|
|
|
export default VideoJS;
|
2021-07-06 21:49:33 +02:00
|
|
|
```
|
|
|
|
|
|
|
|
You can then use it like this: (see [options guide][options] for option information)
|
2021-08-24 05:21:47 +08:00
|
|
|
|
2021-07-06 21:49:33 +02:00
|
|
|
```jsx
|
|
|
|
import React from "react";
|
|
|
|
import VideoJS from './VideoJS' // point to where the functional component is stored
|
|
|
|
|
|
|
|
const App = () => {
|
2021-08-24 05:21:47 +08:00
|
|
|
const playerRef = React.useRef(null);
|
2021-07-06 21:49:33 +02:00
|
|
|
|
|
|
|
const videoJsOptions = { // lookup the options in the docs for more options
|
|
|
|
autoplay: true,
|
|
|
|
controls: true,
|
|
|
|
responsive: true,
|
|
|
|
fluid: true,
|
|
|
|
sources: [{
|
|
|
|
src: '/path/to/video.mp4',
|
|
|
|
type: 'video/mp4'
|
|
|
|
}]
|
|
|
|
}
|
2021-08-24 05:21:47 +08:00
|
|
|
|
|
|
|
const handlePlayerReady = (player) => {
|
|
|
|
playerRef.current = player;
|
|
|
|
|
|
|
|
// you can handle player events here
|
|
|
|
player.on('waiting', () => {
|
|
|
|
console.log('player is waiting');
|
|
|
|
});
|
|
|
|
|
|
|
|
player.on('dispose', () => {
|
|
|
|
console.log('player will dispose');
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
// const changePlayerOptions = () => {
|
|
|
|
// // you can update the player through the Video.js player instance
|
|
|
|
// if (!playerRef.current) {
|
|
|
|
// return;
|
|
|
|
// }
|
|
|
|
// // [update player through instance's api]
|
|
|
|
// playerRef.current.src([{src: 'http://ex.com/video.mp4', type: 'video/mp4'}]);
|
|
|
|
// playerRef.current.autoplay(false);
|
|
|
|
// };
|
|
|
|
|
2021-07-06 21:49:33 +02:00
|
|
|
return (
|
|
|
|
<>
|
|
|
|
<div>Rest of app here</div>
|
2021-08-24 05:21:47 +08:00
|
|
|
|
|
|
|
<VideoJS options={videoJsOptions} onReady={handlePlayerReady} />
|
|
|
|
|
2021-07-06 21:49:33 +02:00
|
|
|
<div>Rest of app here</div>
|
|
|
|
</>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
## React Class Component Example
|
2017-01-26 22:16:52 +01:00
|
|
|
|
2017-08-14 22:02:48 +01:00
|
|
|
It just instantiates the Video.js player on `componentDidMount` and destroys it on `componentWillUnmount`.
|
2017-01-26 22:16:52 +01:00
|
|
|
|
|
|
|
```jsx
|
|
|
|
import React from 'react';
|
|
|
|
import videojs from 'video.js'
|
2021-07-06 21:49:33 +02:00
|
|
|
import video.js/dist/video-js.css
|
2017-01-26 22:16:52 +01:00
|
|
|
|
|
|
|
export default class VideoPlayer extends React.Component {
|
|
|
|
componentDidMount() {
|
2017-08-14 22:02:48 +01:00
|
|
|
// instantiate Video.js
|
2017-01-26 22:16:52 +01:00
|
|
|
this.player = videojs(this.videoNode, this.props, function onPlayerReady() {
|
|
|
|
console.log('onPlayerReady', this)
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
// destroy player on unmount
|
|
|
|
componentWillUnmount() {
|
|
|
|
if (this.player) {
|
|
|
|
this.player.dispose()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// wrap the player in a div with a `data-vjs-player` attribute
|
|
|
|
// so videojs won't create additional wrapper in the DOM
|
|
|
|
// see https://github.com/videojs/video.js/pull/3856
|
|
|
|
render() {
|
|
|
|
return (
|
2021-08-24 05:21:47 +08:00
|
|
|
<div>
|
2018-02-14 00:55:09 +06:00
|
|
|
<div data-vjs-player>
|
|
|
|
<video ref={ node => this.videoNode = node } className="video-js"></video>
|
|
|
|
</div>
|
2017-01-26 22:16:52 +01:00
|
|
|
</div>
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
2017-03-21 17:13:06 -04:00
|
|
|
You can then use it like this: (see [options guide][options] for option information)
|
2017-01-26 22:16:52 +01:00
|
|
|
|
|
|
|
```jsx
|
|
|
|
const videoJsOptions = {
|
2017-02-14 16:41:58 +01:00
|
|
|
autoplay: true,
|
2017-01-26 22:16:52 +01:00
|
|
|
controls: true,
|
|
|
|
sources: [{
|
|
|
|
src: '/path/to/video.mp4',
|
|
|
|
type: 'video/mp4'
|
|
|
|
}]
|
|
|
|
}
|
|
|
|
|
|
|
|
return <VideoPlayer { ...videoJsOptions } />
|
|
|
|
```
|
2017-03-21 17:13:06 -04:00
|
|
|
|
2021-08-24 05:21:47 +08:00
|
|
|
[options]: /docs/guides/options.md
|
2017-05-11 14:33:29 -06:00
|
|
|
|
|
|
|
## Using a React Component as a Video JS Component
|
|
|
|
|
|
|
|
```jsx
|
|
|
|
/**
|
|
|
|
* EpisodeList.js
|
|
|
|
*
|
|
|
|
* This is just a plain ol' React component.
|
|
|
|
* the vjsComponent methods, player methods etc. are available via
|
|
|
|
* the vjsComponent prop (`this.props.vjsComponent`)
|
|
|
|
*/
|
|
|
|
import React, { Component, PropTypes } from 'react';
|
|
|
|
|
|
|
|
class EpisodeList extends Component {
|
|
|
|
render() {
|
|
|
|
return (
|
|
|
|
<div>
|
|
|
|
<h1>{this.props.body}</h1>
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* vjsEpisodeList.js
|
|
|
|
*
|
|
|
|
* Here is where we register a Video JS Component and
|
|
|
|
* mount the React component to it when the player is ready.
|
|
|
|
*/
|
|
|
|
import EpisodeList from './EpisodeList';
|
|
|
|
import ReactDOM from 'react-dom';
|
|
|
|
import videojs from 'video.js';
|
|
|
|
|
|
|
|
const vjsComponent = videojs.getComponent('Component');
|
|
|
|
|
|
|
|
class vjsEpisodeList extends vjsComponent {
|
|
|
|
|
|
|
|
constructor(player, options) {
|
|
|
|
super(player, options);
|
|
|
|
|
|
|
|
/* Bind the current class context to the mount method */
|
|
|
|
this.mount = this.mount.bind(this);
|
|
|
|
|
|
|
|
/* When player is ready, call method to mount React component */
|
|
|
|
player.ready(() => {
|
|
|
|
this.mount();
|
|
|
|
});
|
2021-08-24 05:21:47 +08:00
|
|
|
|
2018-03-08 04:09:06 +11:00
|
|
|
/* Remove React root when component is destroyed */
|
|
|
|
this.on("dispose", () => {
|
|
|
|
ReactDOM.unmountComponentAtNode(this.el())
|
|
|
|
});
|
2017-05-11 14:33:29 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* We will render out the React EpisodeList component into the DOM element
|
|
|
|
* generated automatically by the VideoJS createEl() method.
|
|
|
|
*
|
|
|
|
* We fetch that generated element using `this.el()`, a method provided by the
|
|
|
|
* vjsComponent class that this class is extending.
|
|
|
|
*/
|
|
|
|
mount() {
|
|
|
|
ReactDOM.render(<EpisodeList vjsComponent={this} body="Episodes" />, this.el() );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Make sure to register the vjsComponent so Video JS knows it exists
|
|
|
|
*/
|
|
|
|
vjsComponent.registerComponent('vjsEpisodeList', vjsEpisodeList);
|
|
|
|
|
|
|
|
export default vjsEpisodeList;
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* VideoPlayer.js
|
|
|
|
* Check the above example for how to integrate the rest of this class.
|
|
|
|
*/
|
|
|
|
|
|
|
|
// ...
|
|
|
|
componentDidMount() {
|
2017-08-14 22:02:48 +01:00
|
|
|
// instantiate Video.js
|
2017-05-11 14:33:29 -06:00
|
|
|
this.player = videojs(this.videoNode, this.props, function onPlayerReady() {
|
|
|
|
console.log('onPlayerReady', this)
|
|
|
|
});
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Fetch the controlBar component and add the new vjsEpisodeList component as a child
|
|
|
|
* You can pass options here if desired in the second object.
|
|
|
|
*/
|
|
|
|
this.player.getChild('controlBar').addChild('vjsEpisodeList', {});
|
|
|
|
}
|
|
|
|
// ...
|
|
|
|
```
|