How to stream webcam feed on web page using react js component?

Arjun Chiddarwar picture Arjun Chiddarwar · Dec 13, 2016 · Viewed 17.5k times · Source

I am new to reactJS and trying to build a component.

I want to build a basic utility where I have a video component that shows live webcam feed and there would be a capture button, to capture and store a snap of the feed to disk. I want it to be in a single component ( video feed + capture button)

This code streams the feed in browser but I want it in a component,

<body>
<div id="container">
    <video autoplay="true" id="videoElement">

    </video>
</div>
<script>
 var video = document.querySelector("#videoElement");

navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia || navigator.oGetUserMedia;

if (navigator.getUserMedia) {       
    navigator.getUserMedia({video: true}, handleVideo, videoError);
}

function handleVideo(stream) {
    video.src = window.URL.createObjectURL(stream);
}

function videoError(e) {}
</script>
</body>
</html>

This works fine, but not it's not a component.

I tried following in reaact js but it's not working:

<body>
    <div id="container">

    </div>
    <script type="text/jsx">
        var MyComponent = React.createClass({
            handleVideo: function(stream) {
                video.src = window.URL.createObjectURL(stream);
            },
            videoError: function() {

            },
            render: function() {

            var video = document.querySelector("#videoElement");

            navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia || navigator.oGetUserMedia;

            if (navigator.getUserMedia) {       
                navigator.getUserMedia({video: true}, this.handleVideo, this.videoError);
            }
                return <div>
                        <video autoplay="true" id="videoElement">
                        </video>
                       </div>;
            }
        });
    React.render( <MyComponent />, document.getElementById('container'));
    </script>
    </body>

The error is in handleVideo()

ReferenceError: video is not defined.

My understanding of error is,

since the video tag is coming in later part(in return), it's trying to use before the definition in handleVideo function. i am confused how to make this work.

Thank you!

Answer

Jordan Burnett picture Jordan Burnett · Dec 13, 2016

There are a few things to understand about the way React components work. Firstly according to the React docs:

The render() function should be pure, meaning that it does not modify component state, it returns the same result each time it's invoked, and it does not directly interact with the browser.

You should move initializing your video element to an alternate lifecycle method like componentDidMount to ensure that it is only initialized once.

Secondly, you rarely need to interact with the DOM directly. In this case we can use the component's internal state to manage the src attribute for the video stream, ensuring it only updates after the stream has initialized.

Here's an updated component that might work:

var MyComponent = React.createClass({
  getInitialState: function(){
    return { videoSrc: null }
  },
  componentDidMount: function(){
    navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia || navigator.oGetUserMedia;
    if (navigator.getUserMedia) {
        navigator.getUserMedia({video: true}, this.handleVideo, this.videoError);
    }
  },
  handleVideo: function(stream) {
    // Update the state, triggering the component to re-render with the correct stream
    this.setState({ videoSrc: window.URL.createObjectURL(stream) });
  },
  videoError: function() {

  },
  render: function() {
    return <div>
      <video src={this.state.videoSrc} autoPlay="true" />
    </div>;
    }
});