Quick Tip: Build a Video Player Component in React
In this quick tip, we’re going to create a React video component. This will enable you to define a list of videos and allow your visitors to cycle between them. The component will support Vimeo, YouTube and Dailymotion but you can easily extend it to support other video providers.
By way of a dev environment we’ll use react-hot-boilerplate which comes with hot reloading enabled. This means we can build our component and see the results immediately in the browser, without refreshing the page every time the code changes.
You can find the source code on our GitHub repo, as well as a demo at the bottom of the article.
Starting from a Boilerplate
We’ll start by setting up our working environment from a boilerplate. Assuming you have git installed on your machine, let’s clone the repo by running:
git clone https://github.com/gaearon/react-hot-boilerplate
This will create a folder react-hot-boilerplate
in the directory we’re at. Let’s now navigate to that folder and install dependencies by running:
cd react-hot-boilerplate
npm install
Next, we’ll need to install querystring which we’ll be using later on.
npm install --save query-string
Finally, we can kick things off with:
npm start
If things have gone according to plan, the message Listening at localhost:3000
will appear in the prompt. Webpack will still need to process the files before being able to serve them. After some delay, a sequence of operations should appear in the prompt, ending with webpack: bundle is now VALID
, which means everything is ready to go.
By navigating to http://localhost:3000/ in the browser you should now be able to see ‘Hello, world.’ displayed.
Creating the Component
The first thing to do is to create the component file at src/social-video.js
. For now the minimal code needed for the component to work and some dummy render content will suffice.
import React, {Component} from 'react';
export default class SocialVideo extends Component {
render() {
return (
<h1>Social Video</h1>
);
}
}
Next, in src/App.js
, let’s create a list of videos that we can cycle between using Next and Previous buttons.
import React, { Component } from 'react';
import SocialVideo from './social-video';
var videos = [
{
service: 'youtube',
video: 'https://www.youtube.com/watch?v=XxVg_s8xAms'
},
{
service: 'vimeo',
video: 'https://vimeo.com/151715092'
},
{
service: 'dailymotion',
video: 'http://www.dailymotion.com/video/x3oc771_la-voiture-du-futur_tech'
}
];
export default class App extends Component {
constructor (props) {
super(props);
this.state = {
videoIndex: 0
};
}
goToVideo (index) {
let videoIndex = index;
if (videoIndex < 0) {
videoIndex = videos.length - 1;
} else if (videoIndex >= videos.length) {
videoIndex = 0;
}
this.setState({
videoIndex
});
}
render() {
const {service, video} = videos[this.state.videoIndex];
return (
<div>
<SocialVideo service={service} video={video} width={500} height={270} />
<p>
<span>{service}: </span>
<span>{video}</span>
</p>
<button onClick={this.goToVideo.bind(this, this.state.videoIndex - 1)}>
Previous
</button>
<button onClick={this.goToVideo.bind(this, this.state.videoIndex + 1)}>
Next
</button>
</div>
);
}
}
There’s nothing too fancy going on here. We’re defining an array with data about the videos we want to switch between. In the App
state we’re saving the position in the array that indicates which video is selected. We’re also displaying information about the selected video and rendering our SocialVideo
component. For now the component doesn’t do much, so we need to get to it.
We’ll be passing the video information as props
to the SocialVideo
component and using that information to render the appropriate content. The component won’t have any state of its own. This will make it reusable and predictable, meaning same input equals the same output every time. Here’s the completed component. If you’re following along at home, be sure to have your browser open when you save the file and watch the UI update automatically.
import qs from 'query-string';
import React, {Component, PropTypes} from 'react';
export default class SocialVideo extends Component {
static propTypes = {
service: PropTypes.oneOf(['youtube', 'vimeo', 'dailymotion']).isRequired,
video: PropTypes.string.isRequired
};
static urlMap = new Map([
['youtube', 'http://www.youtube.com/embed/'],
['vimeo', 'https://player.vimeo.com/video/'],
['dailymotion', 'http://www.dailymotion.com/embed/video/']
]);
getIdFromVideoString (vString) {
const urlArr = vString.split('/');
const idString = urlArr[urlArr.length - 1];
const queryParams = qs.extract(vString);
return (queryParams && qs.parse(queryParams).v) || idString || '';
}
render() {
const {service, video, ...htmlTags} = this.props;
const src = `${SocialVideo.urlMap.get(service)}${this.getIdFromVideoString(video)}`;
return (
<iframe
src={src}
frameBorder='0'
webkitAllowFullScreen
mozallowfullscreen
allowFullScreen
{...htmlTags}
/>
);
}
}
Let’s break this down. As you might have noticed we’re including our query-string dependency. This will be used to parse the videos URLs we send to the component.
The component requires two props
, which are defined in propTypes
:
service
— the video providervideo
— the video URL or ID
Now let’s see what we’re doing in the render
function. We start with:
const {service, video, ...htmlTags} = this.props;
What we’re doing here is destructuring the props
to get the service
and video
values, then assigning any remaining props
that may have been passed to the component to the variable htmlTags
.
We now need to process the service
and video
variables to generate a src
variable that we’ll use to create an <iframe>
tag. That’s what the following code does:
const src = `${SocialVideo.urlMap.get(service)}${this.getIdFromVideoString(video)}`;
Here we’re generating a string starting with the default embed URL which is obtained from a static property called urlMap
. The second part of the string consists of the video ID, which is generated by calling the function getIdFromVideoString
.
Now we have calculated the src
variable, we just need to render it to an <iframe>
:
return (
<iframe
src={src}
frameBorder='0'
webkitAllowFullScreen
mozallowfullscreen
allowFullScreen
{...htmlTags}
/>
);
Note how we’re passing htmlTags
preceded by the spread operator (...
), so that if extra props
are sent to the component, such as: className
, style
, width
, height
, etc., they get inserted into the <iframe>
tag. This makes the component more customizable and dynamic.
We can now see our component playing the selected video at http://localhost:3000/. This is also shown in the following demo.
See the Pen XXQrKG by SitePoint (@SitePoint) on CodePen.
Conclusion
In this quick tip I’ve shown you how to make a React video component which allows your users to cycle between a list of videos. We used the react-hot-boilerplate to jump start our dev environment and saw hot reloading in action. The component didn’t have any state of its own, which makes it reusable and predictable (in so far as the same input equals the same output every time). The goal of this quick tip was not only to show you how to specifically build this component, but also to promote good practices whilst doing so.
Is this something you would use? Would you have built it differently? I’d love to hear from you in the comments below.