DEV Community

Cover image for Build a Video Chat App with React Hooks
Arjun Kava for Video SDK

Posted on • Edited on

Build a Video Chat App with React Hooks

It is easy to use functional components with react hooks API. In this tutorial, we are going to use RTC React Video SDK to build video calling app in react js.

Update 1 - 28th Dec, 2021: Refer new video series React Video Chat App with Video SDK

Video SDK React JS SDK makes it easy to build real time video conferencing application. Video SDK handles compatibility with all the browsers, scale up-to 5,000 participants and low latency.

Video SDK RTC React JS SDK supports many features such as

  • 10,000 minutes free each month
  • Completely Low code and serverless.
  • Video API with real-time audio, video and data streams
  • 5,000+ participants support
  • Chat support with rich media.
  • Screen sharing with HD and Full HD.
  • Play realtime video in meeting
  • Connect it with social media such as Facebook, Youtube etc (RTMP out support).
  • Intelligent speaker switch
  • Record your meetings on cloud
  • Customize UI as per your needs.

Index

  1. Create account on Video SDK
  2. Setup Server
  3. Structure of the Project
  4. Start Writing the Code

1. Create account on Video SDK

Start Project at videosdk.live
Create account on Video SDK

Navigate to the the start project button and register yourself either using Google Account or Github.

Prerequisites

Node >= 10.16
Npm >= 5.6
React ≥ 16.8

2. Setup Server

A server will require to perform authentication via JWT token. We are going to use official Node JS server example.

  • Clone following repository and run the server.


$ git clone https://github.com/videosdk-live/videosdk-rtc-nodejs-sdk-example
$ cd nodejs


Enter fullscreen mode Exit fullscreen mode

Note: You can also find other backend language examples in the same repo.

Follow the Node JS Server Setup Guide to run the server.

3. Structure of the Project

You can use react-scripts to generate project template or any other react boilerplate.

Create new project using create-react-app



npx create-react-app videosdk-react-app-v1


Enter fullscreen mode Exit fullscreen mode

This is how your project directory should look like



.
├── node_modules
├── public
├── .env
├── src
 └── api.js
 └── App.jsx
 └── index.css
 └── index.jsx
├── package.json
...
.


Enter fullscreen mode Exit fullscreen mode

Configure Environment Variables

Before writing the code, configure .env variables.

.env



REACT_APP_SERVER_URL="http://localhost:9000"


Enter fullscreen mode Exit fullscreen mode

Note: For production environment, you have to host this server and need to change URL.

Install the official React JS package

Before jumping to anything else, install videosdk react js sdk.



yarn add @videosdk.live/react-sdk


Enter fullscreen mode Exit fullscreen mode

4.Start Writing the Code

We will first setup API calls then after jump to writing the code.

Calling API to generate auth token and meetingId

We will start writing the code with api.js. Before starting any meeting, you have to generate authentication token and meetingId

api.js



const API_BASE_URL = process.env.REACT_APP_SERVER_URL;

// API call to generate authentication token
export const getToken = async () => {
  const res = await fetch(`${API_BASE_URL}/get-token`, {
    method: "GET",
  });

  const { token } = await res.json();
  return token;
};

// API call to create meeting
export const createMeeting = async ({ token }) => {
  const res = await fetch(`${API_BASE_URL}/create-meeting`, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ token }),
  });

  const { meetingId } = await res.json();
  return meetingId;
};



Enter fullscreen mode Exit fullscreen mode

Start with App.jsx

First of all, Let's setup token generation and meetingId logic before working on video calling view.

App Component



import logo from './logo.svg';
import './App.css';
import React, { useEffect, useRef, useState } from "react";
import {
  MeetingProvider,
  MeetingConsumer,
  useMeeting,
  useParticipant,
} from "@videosdk.live/react-sdk";
import { getToken, validateMeeting, createMeeting } from "./api";

function MeetingGrid() {
  return <h1>Meeting Grid</h1>
}

function JoinScreen() {
  return <h1>Join Screen</h1>
}

function ParticipantView(props){
  return <h1>Participant View</h1>
}

function App() {
  const [token, setToken] = useState(null);
  const [meetingId, setMeetingId] = useState(null);

  const getMeetingAndToken = async () => {
    const token = await getToken();
    const meetingId = await createMeeting({ token });

    setToken(token);
    setMeetingId(meetingId);
  };

  useEffect(getMeetingAndToken, []);
  return token && meetingId ? (
    <MeetingProvider
      config={{
        meetingId,
        micEnabled: true,
        webcamEnabled: false,
        name: "Participant Name",
      }}
      token={token}
    >
      <MeetingConsumer>
        {() => <MeetingGrid />}
      </MeetingConsumer>
    </MeetingProvider>
  ) : (
    <JoinScreen />
  );
}

export default App;


Enter fullscreen mode Exit fullscreen mode

React JS SDK provides two important hooks API:

  • useMeeting: Responsible to handle meeting environment.
  • useParticipant: Responsible to handle

Also, React Provider and Consumer to listen changes in meeting environment.

  • MeetingProvider: Meeting Provider is Context.Provider that allows consuming components to subscribe to meeting changes.
  • MeetingConsumer: Meeting Consumer is Context.Consumer that subscribes to meeting changes.

Implement Join Screen

We will start with join screen where user can either create meeting or can join using meetingId.

It contains two simple features:

  1. Create New Meeting
  2. Join the meeting

JoinScreen Component



function JoinScreen() {
  <div>
    <input type="text" placeholder="Enter Meeting Id" onChange={(e) => {setMeetingId(e.target.value)}}  />
    <button  onClick={getMeetingAndToken}>
      Join
    </button>
    <button  onClick={getMeetingAndToken}>
      Create Meeting
    </button>
  </div>
}


Enter fullscreen mode Exit fullscreen mode

Implementing Meeting Grid

Meeting grid will include whole meeting interface. It will be responsible for:

  1. Turn On and Off Mic
  2. Turn On and Off WebCam
  3. Participant View


const {
   join, 
   leave,  
   toggleMic,
   toggleWebcam,
   toggleScreenShare
} = useMeeting();


Enter fullscreen mode Exit fullscreen mode

Let's get started and implement it one by one. useMeeting hook will help you to perform join, leave, toggleMic etc.

Meeting Grid Component



// Helper function for participant loop.
const chunk = (arr) => {
  const newArr = [];
  while (arr.length) newArr.push(arr.splice(0, 3));
  return newArr;
};

function MeetingGrid(props) {
  const [joined, setJoined] = useState(false)
  const {
    join, 
    leave,  
    toggleMic,
    toggleWebcam,
    toggleScreenShare
  } = useMeeting()
  const { participants } = useMeeting();
  const joinMeeting = () => {
    setJoined(true)
    join()
  }
  return (
    <div>
      <header>Meeting Id: {props.meetingId}</header>
      {joined ? 
      (
        <div >
          <button  onClick={leave}>
            Leave
          </button>
          <button  onClick={toggleMic}>
            toggleMic
          </button>
          <button  onClick={toggleWebcam}>
            toggleWebcam
          </button>
          <button  onClick={toggleScreenShare}>
            toggleScreenShare
          </button> 
        </div>
      ) 
      : (<button  onClick={joinMeeting}>
        Join
      </button>)}
      <div
        className="wrapper"
      >
        {chunk([...participants.keys()]).map((k) => (
          <div className="box" key={k} style={{ display: "flex" }}>
            {k.map((l) => (
              <ParticipantView key={l} participantId={l} />
            ))}
          </div>
        ))}
      </div>

    </div>
  )
}


Enter fullscreen mode Exit fullscreen mode

Implementing Participant View

To implement participant grid, we are going to use react-simple-flex-grid. It will be helpful to maintain video grid.

Let's first add this package.



yarn add react-simple-flex-grid


Enter fullscreen mode Exit fullscreen mode

Import react-simple-flex-grid in App Component



import { Row, Col } from 'react-simple-flex-grid';
import "react-simple-flex-grid/lib/main.css";


Enter fullscreen mode Exit fullscreen mode

Participant view will include three major features:

  1. Enable/Disable WebCam
  2. Enable/Disable Mic
  3. Share your screen.

Let's explore each of it. Before starting it, we have to understand useRef of audio, video and screen share element



const webcamRef = useRef(null);
const micRef = useRef(null);
const screenShareRef = useRef(null);


Enter fullscreen mode Exit fullscreen mode

Apart from that, useParticipant hook will help you to handle mic, webcam and screen share.



 const {
    displayName,
    webcamStream,
    micStream,
    screenShareStream,
    webcamOn,
    micOn,
    screenShareOn
  } = useParticipant(props.participantId);


Enter fullscreen mode Exit fullscreen mode

After getting the stream, you can add track to using MediaStream API. For example, check out below code to add reference of webCam



 const mediaStream = new MediaStream();
 mediaStream.addTrack(webcamStream.track);

 webcamRef.current.srcObject = mediaStream;
 webcamRef.current
   .play()
   .catch((error) =>
     console.error("videoElem.current.play() failed", error));


Enter fullscreen mode Exit fullscreen mode

After adding the reference in on loading state of component, you can

ParticipantView Component



function ParticipantView(props) {
  const webcamRef = useRef(null);
  const micRef = useRef(null);
  const screenShareRef = useRef(null);

  const {
    displayName,
    webcamStream,
    micStream,
    screenShareStream,
    webcamOn,
    micOn,
    screenShareOn
  } = useParticipant(props.participantId);

  useEffect(() => {
    if (webcamRef.current) {
      if (webcamOn) {
        const mediaStream = new MediaStream();
        mediaStream.addTrack(webcamStream.track);

        webcamRef.current.srcObject = mediaStream;
        webcamRef.current
          .play()
          .catch((error) =>
            console.error("videoElem.current.play() failed", error)
          );
      } else {
        webcamRef.current.srcObject = null;
      }
    }
  }, [webcamStream, webcamOn]);

  useEffect(() => {
    if (micRef.current) {
      if (micOn) {
        const mediaStream = new MediaStream();
        mediaStream.addTrack(micStream.track);

        micRef.current.srcObject = mediaStream;
        micRef.current
          .play()
          .catch((error) =>
            console.error("videoElem.current.play() failed", error)
          );
      } else {
        micRef.current.srcObject = null;
      }
    }
  }, [micStream, micOn]);

  useEffect(() => {
    if (screenShareRef.current) {
      if (screenShareOn) {
        const mediaStream = new MediaStream();
        mediaStream.addTrack(screenShareStream.track);

        screenShareRef.current.srcObject = mediaStream;
        screenShareRef.current
          .play()
          .catch((error) =>
            console.error("videoElem.current.play() failed", error)
          );
      } else {
        screenShareRef.current.srcObject = null;
      }
    }
  }, [screenShareStream, screenShareOn]);


  return (
    <div key={props.participantId} >
      <audio ref={micRef} autoPlay />
      {webcamRef ||  micOn ? (<div>
      <h2>{displayName}</h2>
      <video
        height={"100%"}
        width={"100%"}
        ref={webcamRef}
        autoPlay
      />
      </div>) : null }
      {screenShareOn ? (
      <div>
        <h2>Screen Shared</h2>
        <video
          height={"100%"}
          width={"100%"}
          ref={screenShareRef}
          autoPlay
        />
      </div>) : null }
      <br/>
      <span>Mic:{micOn ? "Yes": "No"}, Camera: {webcamOn ? "Yes" : "No"}, Screen Share: {screenShareOn ? "Yes" : "No"}</span>
    </div>
  );
}


Enter fullscreen mode Exit fullscreen mode

You can implement further features like cloud recording, chat, whiteboard, social media live etc by refereeing official guide of Video SDK

Find out code whole code on videosdk-react-sdk-tutorial-example

Launching: Video SDK React JS

Conclusion

That's how we can integrate video calling API using React JS hooks. You can also check official example videosdk-rtc-react-js-example to extend this application with lots of other amazing features.

You can use this basic video chat app and change a few lines of code for live audio/video streaming.

Top comments (1)

Collapse
 
mrcflorian profile image
Info Comment hidden by post author - thread only accessible via permalink
mrcflorian

Thanks a lot for the tutorial, very helpful! I'd also recommend as an alternative trying to use Firebase as a server. You can check out projects such as this React Native video chat app instamobile.io/app-templates/video...

Some comments have been hidden by the post's author - find out more