React Quickstart Guide

Getting started

Hello there! In this guide, we'll build a video conferencing application using our React SDK. We'll be using functional components with the powerful hooks provided by our SDK and build an app where you can have video call with your friends.

TL;DR - You can find the link to the complete example over here.

Prerequisites

To get started you should be familiar with basics of React.

Installing the dependencies

npm install --save @100mslive/hms-video@latest @100mslive/hms-video-react@latest

Initializing the SDK

Let us start with initializing the libraries. We need to wrap the entire application with <HMSRoomProvider /> component.

This will let us use the hooks for state and actions.

src/index.jsx
import { StrictMode } from "react"; import ReactDOM from "react-dom"; import { HMSRoomProvider } from "@100mslive/hms-video-react"; import App from "./App"; const rootElement = document.getElementById("root"); ReactDOM.render( <StrictMode> <HMSRoomProvider> <App /> </HMSRoomProvider> </StrictMode>, rootElement );

hmsStore will hold the complete state of the application such as details of all the participants. We can also visualize this state at any time using the devtools extension.

hmsActions will help us perform actions such as joining the room, mute our audio and send messages.

Concepts

  • Room: When we join a conference call, the participants are said to be in a video call room.
  • Peer: A participant in the video call. You are the local peer while others are remote peers.
  • Track: Media. There are two types of track a peer can have - audio and video.

Joining a room

To join a room (a video call), we need to call the join method on hmsActions and it requires us to pass a config object. The config object must be passed the following fields:

  • userName: The name of the user. This is the value that will be set on the peer object and be visible to everyone connected to the room.
  • authToken: A client-side token that is used to authenticate the user. You can read about how to generate this token here.

For our application, let us collect both of these fields from the user using a form. Let's create a JoinForm component and add it to the application.

src/JoinForm.jsx
import { useState } from "react"; function JoinForm() { const hmsActions = useHMSActions(); const [inputValues, setInputValues] = useState({ name: "", token: "" }); const handleInputChange = (e) => { setInputValues((prevValues) => ({ ...prevValues, [e.target.name]: e.target.value })); }; const handleSubmit = (e) => { e.preventDefault(); hmsActions.join({ userName: inputValues.name, authToken: inputValues.token }); }; return ( <form onSubmit={handleSubmit}> <h2>Join Room</h2> <div className="input-container"> <input value={inputValues.name} onChange={handleInputChange} id="name" type="text" name="name" placeholder="Your name" /> </div> <div className="input-container"> <input value={inputValues.token} onChange={handleInputChange} id="token" type="text" name="token" placeholder="Auth token" /> </div> <button className="btn-primary">Join</button> </form> ); } export default JoinForm;

Let's add this form to our <App> component.

src/App.jsx
export default function App() { return ( <div className="App"> <JoinForm /> </div> ); }

Join form

Congratulations! you now have an audio-only conference ready to use. If you have a friend join from another device, you can have a nice friendly chat with them.

Leaving the room

Before we go ahead with adding video, let us add a way to leave the room as well. We can call the leave method on hmsActions to leave the room.

We'll set up the leave method to be called whenever the user closes the window or refreshes the tab.

src/App.jsx
export default function App() {
const hmsActions = useHMSActions();
useEffect(() => {
window.onunload = () => {
hmsActions.leave();
};
}, [hmsActions]);
return ( <div className="App"> <JoinForm /> </div> ); }

Adding video tiles

Let us next add a way to show a tile for every participant in the room. We'll need a list of peers connected to the room.

Fetching information from state

At any point in time we can get a list of peers with:

import { useHMSStore, selectPeers } from '@100mslive/hms-video-react'; function Component() {} const peers = useHMSStore(selectPeers); return <Peers peers={peers} />; }

Let's take a moment to discuss how hmsStore works. The store maintains the state of the video call which includes the list of peers, the connection state of the room, the tracks, track states etc. We can use "selectors" that return a slice of the state to get the data piece we're interested in.

The hmsStore is also reactive, which means any component using the HMSStore hook will re-render when the slice of the state, it listens to, changes. This allows us to write declarative code.

Let us now create a Conference component that will render a list of peers. We'll get the peers from store and render them. Our component will get rerendered if this list of peers changes.

src/Conference.jsx
import { selectPeers, useHMSStore } from "@100mslive/hms-video-react"; import React from "react"; import Peer from "./Peer"; function Conference() { const peers = useHMSStore(selectPeers); return ( <div className="conference-section"> <h2>Conference</h2> <div className="peers-container"> {peers.map((peer) => ( <Peer key={peer.id} peer={peer} /> ))} </div> </div> ); } export default Conference;

For each peer, we'll render a <video> element and a <div> element with their name. In order to render the video, we need to call attachVideo method of hmsActions, which accepts a trackId and a DOM element.

src/Peer.jsx
import { selectVideoTrackByPeerID, useHMSActions, useHMSStore } from "@100mslive/hms-video-react"; import { useRef, useEffect } from "react"; function Peer({ peer }) { const videoRef = useRef(null); const hmsActions = useHMSActions(); const videoTrack = useHMSStore(selectVideoTrackByPeerID(peer.id)); useEffect(() => { if (videoRef.current && videoTrack) { if (videoTrack.enabled) { hmsActions.attachVideo(videoTrack.id, videoRef.current); } else { hmsActions.detachVideo(videoTrack.id, videoRef.current); } } }, [videoTrack, hmsActions]); return ( <div className="peer-container"> <video ref={videoRef} className={`peer-video ${peer.isLocal ? "local" : ""}`} autoPlay muted playsInline /> <div className="peer-name"> {peer.name} {peer.isLocal ? "(You)" : ""} </div> </div> ); } export default Peer;

Note that height and width CSS properties need to be set on the <video> element to render the peer's video.

Changing UI based on connection state

Right now, our join form shows even after we have joined the room. We need a way to know the connection state of the room and hide the form after we've connected.

We can do this with selectIsConnectedToRoom selector.

src/App.jsx
import "./styles.css"; import JoinForm from "./JoinForm"; import Conference from "./Conference"; import { useEffect } from "react";
import { selectIsConnectedToRoom, useHMSActions, useHMSStore } from "@100mslive/hms-video-react";
export default function App() {
const isConnected = useHMSStore(selectIsConnectedToRoom);
const hmsActions = useHMSActions(); useEffect(() => { window.onunload = () => {
if (isConnected) {
hmsActions.leave(); } };
}, [hmsActions, isConnected]);
return ( <div className="App"> <Header />
{isConnected ? (
<Conference />
) : (
<JoinForm />
)}
</div> ); }

Muting/unmuting local tracks

Right now we are publishing both audio and video feed of the user whenever they join the room. We may want to allow the user to mute/unmute their own tracks - both audio and video.

Let's add 2 buttons on the bottom of the page and call the methods on hmsActions to mute/unmute the local tracks.

src/Footer.jsx
import { selectIsLocalAudioEnabled, selectIsLocalVideoEnabled, useHMSActions, useHMSStore } from "@100mslive/hms-video-react"; function Footer() { const videoEnabled = useHMSStore(selectIsLocalVideoEnabled); const audioEnabled = useHMSStore(selectIsLocalAudioEnabled); const hmsActions = useHMSActions(); const toggleAudio = () => { hmsActions.setLocalAudioEnabled(!audioEnabled); }; const toggleVideo = () => { hmsActions.setLocalVideoEnabled(!videoEnabled); }; return ( <div className="control-bar"> <button className="btn-control" onClick={toggleAudio}> {audioEnabled ? "Mute" : "Unmute"} </button> <button className="btn-control" onClick={toggleVideo}> {videoEnabled ? "Hide" : "Unhide"} </button> </div> ); } export default Footer;

We fetch the current state of the local audio and video and toggle them whenever the buttons are clicked.

Mute/Unmute

And finally let's add this component to the <App> component to render the buttons only when we are connected to the room.

src/App.js
import Footer from './Footer';
export default function App() { const isConnected = useHMSStore(selectIsConnectedToRoom); const hmsActions = useHMSActions(); useEffect(() => { window.onunload = () => { if (isConnected) { hmsActions.leave(); } }; }, [hmsActions, isConnected]); return ( <div className="App"> <Header /> {isConnected ? (
<>
<Conference />
<Footer />
</>
) : ( <JoinForm /> )} </div> ); }

That wraps it up for this guide. We hope you had fun. There are plenty of cool stuff which can be done with our SDK, be sure to check the features section for more information. -->

Here's the complete example.