reactjs – My React/WebRTC app is rendering multiple videos on every change

I’m creating a video chat app where users join a room via url. However, when a new user joins the video appears four times, and four times again on any change. I basically get multiple videos and userIds generated.

I’m using React frontend with Express and Peerjs.

This is my component…

import { CopyToClipboard } from "react-copy-to-clipboard";
import { Peer } from 'peerjs';
import { useParams  } from 'react-router';
import "./Chaterio.css";
import io from "socket.io-client";
import styled from "styled-components";

const peer = new Peer(undefined, {
  host: "https://stackoverflow.com/", 
  port: 9001,
})

const socket = io.connect("http://localhost:9000");


const VideoCall = () => {

  const [localStream, setLocalStream] = useState(null);
  const [peers, setPeers] = useState({})
  const videoGridRef = useRef(null);
  const myVideo = useRef();
  const { roomId } = useParams();

  useEffect(() => {  
 
    console.log("useEffect started...")

    peer.on("open", (id) => {
      socket.emit("join-room", roomId, id);
    });
  
    navigator.mediaDevices.getUserMedia({
        video: true,
        audio: true
    })
      .then((localStream) => {
        setLocalStream(localStream);
        if (myVideo.current) {
          myVideo.current.srcObject = localStream
          myVideo.current.muted = true
        };

        // receive calls by listening to the on call event
        peer.on('call', call => {
          call.answer(localStream)
          const video = document.createElement('video')
          call.on('stream', userVideoStream => {
             addVideoStream(video, userVideoStream);
             console.log("uservideostream ", userVideoStream)
          })
        });

        socket.on("user-connected", (userID) => {
          connectToNewUser(userID, localStream)
        });

        socket.on("user-disconnected", (userId) => {
          console.log("user-disconnected", userId)
          if (peers[userId]) peers[userId].close();

        });

      });
  }, []);
  


  const 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()
    })
    setPeers(prevPeers => ({...prevPeers, [userId]: call}))
  };


  const addVideoStream = (video, stream) => {
    video.srcObject = stream;
    video.addEventListener("loadedmetadata", () => {
      video.play();
    });
    if (videoGridRef.current) {
      videoGridRef.current.appendChild(video);
    }
  };


  return (
    <>
      <OuterContainer>
        <Header><AlinkHeader href="/">Chaterio</AlinkHeader></Header>
          <Container>
            <CopyToClipboard text={roomId} style={{ marginBottom: ".5rem" }}>
                <Button variant="contained" color="primary" >
                    Copy Room Id
                </Button>
            </CopyToClipboard>
          </Container>
          <VideoContainer>
            <VideoDrag >
              {localStream && <video id="myVideo" draggable="true" playsInline muted ref={myVideo} autoPlay width={500} height={500} />}
            </VideoDrag>
              <div id="video-grid" ref={videoGridRef} />
          </VideoContainer>
        
          <SectionOuterButtons>
              <SectionInnerButtons>

                  <a href="/"><RoomButton>Leave Room</RoomButton></a>
                  <a href="/room"><RoomButton>Join Room</RoomButton></a>

              </SectionInnerButtons>
          </SectionOuterButtons>
      </OuterContainer>
    </>
  );
};

This is my server…


       const express = require('express')
       const app = express()
    
    
       const http = require('http');
       const server = http.createServer(app);
    
       const io = require('socket.io')(server);
    
       app.use(express.static('public'))
    
       io.on('connection', socket => {
           socket.on('join-room', (roomId, userId) => {
               socket.join(roomId)
               socket.to(roomId).emit('user-connected', 
       userId)
    
            socket.on('disconnect', () => {
                socket.to(roomId).emit('user-disconnected', 
       userId)
               })
           })
       })
    
       server.listen(3000)

…and I create the room id with uuid as follows…

import React, { useCallback } from "react";
import styled from "styled-components";
import { useNavigate } from 'react-router-dom';

const { v4: uuidV4 } = require('uuid')

const HomePage = () => {

    const navigate = useNavigate();
    const handleJoinRoom = useCallback(() => {
        const roomId = uuidV4();
        navigate(`/videocall/${roomId}`)
    }, [navigate]);


    return (
        <ContainerHome>
            <Header>Chaterio</Header>
            <SectionOuterButtons>
                <SectionInnerButtons>

                    <a href="/chaterio"><RoomButton>New Room</RoomButton></a>
                    <a href="/room"><RoomButton>Join Room</RoomButton></a>

                </SectionInnerButtons>
            </SectionOuterButtons>

            <SectionSearch>
                <InputField id="RoomName" name="RoomName" type="text" placeholder="Enter Room Code"></InputField>
                <SubmitButton onClick={handleJoinRoom} type="submit">Start meeting</SubmitButton>
            </SectionSearch>


        </ContainerHome>
    );
};

Read more here: Source link