EN
React - play web camera on video element (custom WebCamera component)
3 points
In this short article, you can see how in React create custom web camera component using video element and stream video to it.
Example preview:

In this example, we present how to create reusable WebCamera
component to which we can pass the following properties:
width
-WebCamera
component width inpx
(equals to video width),height
-WebCamera
component height inpx
(equals to video height),onReady
- function to be executed once theWebCamera
component is ready,onError
- function to be executed when some error occurs.
Note:
It is important to be sure the web camera is connected properly, permissions for camera are granted and it is not used by any other application.
xxxxxxxxxx
1
// import React from 'react';
2
3
// -- camera utils -----------------------------
4
5
const playStream = (video, stream, callback) => {
6
const handleLoaded = () => {
7
video.removeEventListener('loadedmetadata', handleLoaded);
8
video.play();
9
if (callback) {
10
callback(stream);
11
}
12
};
13
video.addEventListener('loadedmetadata', handleLoaded);
14
video.srcObject = stream;
15
};
16
17
const stopStream = (stream) => {
18
for (const track of stream.getTracks()) {
19
track.stop();
20
}
21
};
22
23
const playCamera = (video, preferedWidth, preferedHeight, onReady = null, onError = null, audioConstraints = null, videoConstraints = null) => {
24
let _stream = null;
25
let _destroyed = false;
26
const constraints = {
27
video: {
28
width: preferedWidth,
29
height: preferedHeight,
30
videoConstraints
31
},
32
audio: audioConstraints
33
};
34
const promise = navigator.mediaDevices?.getUserMedia?.(constraints);
35
if (promise) {
36
promise
37
.then((stream) => {
38
if (_destroyed) {
39
stopStream(stream);
40
} else {
41
_stream = stream;
42
playStream(video, stream, onReady);
43
}
44
})
45
.catch((error) => {
46
if (onError) {
47
onError(`${error.name}: ${error.message}`);
48
}
49
});
50
} else {
51
if (onError) {
52
onError('Camera API is not supported.');
53
}
54
}
55
return () => {
56
if (_destroyed) {
57
return;
58
}
59
if (_stream) {
60
stopStream(_stream);
61
_stream = null;
62
}
63
_destroyed = true;
64
};
65
};
66
67
// -- react hooks ------------------------------
68
69
// Wraps action function with function that doesn't change its reference.
70
// It is useful when we want to pass a function to component as prop preventing unnecessary re-rendering on reference change.
71
//
72
const useProxy = (action) => {
73
const state = React.useMemo(
74
() => ({
75
wrapper: (args) => {
76
if (state.action) {
77
return state.action(args);
78
}
79
return undefined;
80
},
81
}),
82
[]
83
);
84
state.action = action;
85
return state.wrapper;
86
};
87
88
// -- react components -------------------------
89
90
const WebCamera = ({ width, height, audioConstraints, videoConstraints, onReady, onError }) => {
91
const ref = React.useRef();
92
const handleReady = useProxy(onReady); // by using proxy, onReady is wrapped in function which reference doesn't change
93
const handleError = useProxy(onError); // by using proxy, onError is wrapped in function which reference doesn't change
94
React.useEffect(
95
() => playCamera(ref.current, width, height, handleReady, handleError, audioConstraints, videoConstraints),
96
[width, height] // by using useProxy, we don't need to track onReady and onError functions
97
);
98
return <video ref={ref} width={width} height={height} />;
99
};
100
101
102
103
// Usage example:
104
105
const App = () => {
106
const handleReady = (stream) => {
107
console.log('Web camera is ready and working');
108
};
109
const handleError = (error) => {
110
console.error(error);
111
};
112
return (
113
<div>
114
<WebCamera width={640} height={480} onReady={handleReady} onError={handleError} />
115
</div>
116
);
117
};
118
119
const root = document.querySelector('#root');
120
ReactDOM.render(<App />, root);
It is possible to configure audio and video constraints manually by:
xxxxxxxxxx
1
// https://developer.mozilla.org/en-US/docs/Web/API/Media_Capture_and_Streams_API/Constraints
2
3
// navigator.mediaDevices.getUserMedia({
4
const audioConstraints = { // audio: {
5
sampleSize: 16, // sampleSize: 16,
6
channelCount: 2 // channelCount: 2
7
}; // },
8
const videoConstraints = { // video: {
9
width: 1920, // width: 1920,
10
height: 1080, // height: 1080
11
}; // }
12
// });
13
return (
14
<WebCamera
15
width={640}
16
height={480}
17
audioConstraints={audioConstraints}
18
videoConstraints={videoConstraints}
19
onReady={handleReady}
20
onError={handleError}
21
/>
22
);
When a web camera is accessed from React you should see notification to permit using it. Just let use it by desired website and remove permissions when it is not needed.
