Quick Tip: Build a Video Player Component in React

Bruno Mota
Share

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 provider
  • video — 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.