I wanted to add an video call feature with WebRTC into my chat webapp. So after writing the code i tested the code. -> No video and in the console the error "Uncaught (in promise) TypeError: Cannot set properties of null (setting ‘srcObject’)"
screenshot error message
My code:
//CallProvider
import React, { createContext, useState, useRef, useEffect } from 'react';
import Peer from 'simple-peer';
import io from 'socket.io-client';
export const VideoCallContext = createContext();
const socket = io('http://localhost:5001');
export function CallProvider({ conv, id, children }) {
const videoGrid = document.querySelector('#video-grid');
const [stream, setStream] = useState(null);
const myVideoRef = useRef(null);
const peer = new Peer({
trickle: false,
stream,
});
const peers = {};
useEffect(() => {
navigator.mediaDevices
.getUserMedia({
video: true,
audio: true,
})
.then((currentStream) => {
setStream(currentStream);
myVideoRef.current.srcObject = currentStream.streams[0];
});
socket.on('user-connected', (userId) => {
connectToNewUser(userId, stream);
});
});
socket.on('user-disconnected', (userId) => {
if (peers[userId]) peers[userId].close();
});
function joinCall() {
peer.on('signal', (data) => {
socket.emit('join-call', {
call: conv,
userId: id,
});
});
}
function leaveCall() {
socket.emit('leave-call', {
call: conv,
userId: id,
});
navigator.mediaDevices.getUserMedia({
video: false,
audio: false,
});
}
function connectToNewUser(userId, stream) {
const call = peer.call(userId, stream);
const video = document.createElement('video');
call.on('stream', (userVideoStream) => {
addVideoStream(video, userVideoStream);
});
call.on('close', () => {
video.remove();
});
}
function addVideoStream(video, stream) {
video.srcObject = stream;
video.addEventListener('loadedmetadata', () => {
video.play();
video.playsInline = true;
});
videoGrid.append(video);
}
const value = {
stream,
myVideoRef,
joinCall,
leaveCall,
};
return (
<VideoCallContext.Provider value={value}>
{children}
</VideoCallContext.Provider>
);
}
// FormCall
//use WebRTC from simplepeer
import React, { useContext } from 'react';
import { Button } from 'react-bootstrap';
import { VideoCallContext } from '../contexts/CallProvider';
export default function FormCall({ id, conv, closeWindow }) {
const { stream, myVideoRef, joinCall, leaveCall } =
useContext(VideoCallContext);
const conversation = conv;
function closeCall() {
leaveCall(id);
closeWindow();
}
return (
<>
<style>
{`
#video-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(210px, 230px));
grid-auto-rows: auto;
grid-gap: 5px;
}
`}
{`
video {
width: 100%;
aspect-ratio: 1/1;
object-fit: cover;
object-position: center;
border-radius: 10px;
overflow: hidden;
}
`}
</style>
<div className="pb-2" id="video-grid">
<video playsInline muted ref={myVideoRef} autoPlay></video>
</div>
<div className="d-flex flex-row justify-content-around border-top pt-2">
<Button
onClick={closeCall}
className="rounded-circle position-relative"
style={{ height: '40px', width: '40px' }}
>
<i
className="bi bi-telephone-x-fill position-absolute"
style={{ left: '28%', top: '20%' }}
/>
</Button>
</div>
</>
);
}
My installed packages are:
packages
I have looked for an solution for the error. Nothing that is a solution for my problem.
I also have changed the "currentStream" to "currentStream.streams[0]", nothing changed.
2
Answers
When you set
const myVideoRef = useRef(null)
), you’re settingmyVideoRef.current
tonull
.If you need to the set
srcObject
property in your ref:const myVideoRef = useRef({ srcObject: null })
.Now
myVideoRef.current.srcObject
exists and can be set.Try
const value = {
stream:stream,
myVideoRef:myVideoRef,
joinCall:joinCall,
leaveCall:leaveCall,
};
Also i would avoid returning *.Provider itself.
Wrap CallProvider and it’s children like this:
If You mreturn instance of Context.Provider as Component, then every state mutation rerenders Your Context . The Context is innescesarry then.
If Your Context fully wraps dependant DOM snippet, then Your Context values are stable.
At least one of these two has to be changed to solve Your problem.
P.S.
As Wesley LeMahieu found ,hence i would use useRef() instead of useRef(null).