Monday, March 27, 2023
HomeC#Video-Calling React App with Agora and Syncfusion

Video-Calling React App with Agora and Syncfusion

Video calling has turn out to be a vital a part of staff collaboration as groups are extra geographically numerous than ever.

Many people work remotely or in a hybrid setup, leading to staff members in several components of the world. No matter their location, video calls enable groups to attach with a single click on and get the job achieved.

Agora is an internet service that gives a real-time collaboration mechanism utilizing voice, video, and messaging, and Syncfusion has UI element libraries that assist builders shortly create an internet software with a wealthy set of predefined and extensible elements.

On this weblog, we’ll create a video-calling net app in React utilizing Syncfusion React elements and Agora, the place customers with the identical channel title (assembly code) can collaborate.

Let’s get began.

Organising Agora

Log in to Agora, navigate to the console, and arrange the token. We want the token, app ID, and channel title to hitch a channel.

Setting up the Agora

For testing, we’re going to use the net dashboard supplied by Agora, the place we are going to create a dummy channel.

Agora Web Dashboard

Then via our React app, we are going to be a part of that channel.

Syncfusion React UI elements are the builders’ option to construct user-friendly net functions. You deserve them too.

Discover Now

React app for video calling

Create a contemporary occasion of create-react-app utilizing the next command:

npx create-react-app video-call

Set up the next dependencies:



It is a React SDK that comes with important hooks that make it simple to create purposeful elements with Agora companies.


"@syncfusion/ej2-icons": "^20.3.56",
"@syncfusion/ej2-layouts": "^20.3.58",
"@syncfusion/ej2-react-buttons": "^20.3.58",
"@syncfusion/ej2-react-inputs": "^20.3.57",
"@syncfusion/ej2-react-layouts": "^20.4.38",

It is a set of UI elements that we’ll want throughout improvement.

Now that we have now all of the dependencies put in, let’s start creating the applying.

The appliance is split into two components:

  • A touchdown web page the place the person enters the channel title they need to be a part of.
  • A video web page the place all of the customers which have joined the channel are listed.

Entry file

We’ve an entry file the place, primarily based on whether or not the person has joined the channel, we are going to present the touchdown web page or the video web page.


import React, { useState } from "react";
import VideoCall from "./VideoCall";
import ChannelForm from "./ChannelForm";
import "./App.css";

const App = () => {
  const [inCall, setInCall] = useState(false);
  const [channelName, setChannelName] = useState("");
  return (
  	{inCall ? (
    	<VideoCall setInCall={setInCall} channelName={channelName} />
  	) : (
    	<ChannelForm setInCall={setInCall} setChannelName={setChannelName} />

export default App;

Prime 3 causes to decide on the Syncfusion React element suite:

  • 70+ UI elements
  • Modular structure
  • Optimum person expertise

Discover Now

Touchdown web page

The touchdown web page of our software is the place the person enters the channel title they need to be a part of.

Landing page of the React video calling app

The web page could have an enter factor and a button. The enter factor will settle for the channel title, persist it within the state, and ahead it to the video name element via which the present person joins the channel.

Syncfusion already has a wealthy set of buttons and enter packing containers that we’re going to make the most of right here.

Additionally, we are going to preserve a flag simply to find out if the present person has efficiently joined the channel after which we will replace the view.


import React from "react";
import { TextBoxComponent } from "@syncfusion/ej2-react-inputs";
import { ButtonComponent } from "@syncfusion/ej2-react-buttons";
import "@syncfusion/ej2-base/kinds/materials.css";
import "@syncfusion/ej2-inputs/kinds/materials.css";
import "@syncfusion/ej2-buttons/kinds/materials.css";
import "@syncfusion/ej2-layouts/kinds/materials.css";

const ChannelForm = (props) => { const { setInCall, setChannelName } = props; return ( <div className="e-card wrapper"> <div className="wrapper-inner"> <h1 className="heading">Be part of a Assembly</h1> <kind className="be a part of"> <TextBoxComponent kind="textual content" placeholder="Enter Channel Identify" floatLabelType="Auto" enter={({ worth }) => setChannelName(worth)} cssClass="e-outline" /> <ButtonComponent kind="submit" cssClass="e-info" fashion={{ fontSize: "18px", padding: "10px 20px" }} onClick={(e) => { e.preventDefault(); setInCall(true); }} > Be part of </ButtonComponent> </kind> </div> </div> ); };
export default ChannelForm;

Video web page

The video web page is the principle mother or father element the place all of the enterprise logic is. This element has two subcomponents:

  • Controls the place the controls to mute, unmute, and go away the channel are.
  • Dashboard the place all of the customers who’ve joined the channel are proven.

We’re additionally going to make use of two hooks supplied by the Agora-React-SDK that assist us do the next:

  • Get the consumer particulars and be a part of the channel.
  • Get the digital camera and microphone particulars.

These hooks are the important thing to creating the video name service in React as a result of they summary all of the logic.

A to Z about Syncfusion’s versatile React elements and their characteristic set.

Learn Now


We have to present the essential configurations for initializing the consumer. They’re the essential mode and codec specs.

Confer with the next code:

import { createClient, createMicrophoneAndCameraTracks } from "agora-rtc-react";

const config = { mode: "rtc", codec: "vp8", };
perform useAgora() { const useClient = createClient(config); const useMicrophoneAndCameraTracks = createMicrophoneAndCameraTracks(); return [useClient, useMicrophoneAndCameraTracks]; }
export default useAgora;

Now that we have now the hooks in place, we will use the identical consumer all through the applying.

Utilizing these hooks, we’ll create a brand new occasion for the present person and be a part of the channel.

Confer with the next code instance:


import React, { useEffect, useState } from "react";
import useAgora from "./Hook";
import Controls from "./Controls";
import WebDashboard from "./Dashboard";

const appId = ""; //ENTER APP ID HERE const token = ""; // ENTER TOKEN HERE
const VideoCall = (props) => { const { setInCall, channelName } = props; const [useClient, useMicrophoneAndCameraTracks] = useAgora(); const [users, setUsers] = useState([]); const [start, setStart] = useState(false); const consumer = useClient(); const { prepared, tracks } = useMicrophoneAndCameraTracks(); useEffect(() => { // perform to initialise the SDK let init = async (title) => { consumer.on("user-published", async (person, mediaType) => { await consumer.subscribe(person, mediaType); console.log("subscribe success"); if (mediaType === "video") { setUsers((prevUsers) => { return [...prevUsers, user]; }); } if (mediaType === "audio") { person.audioTrack?.play(); } }); consumer.on("user-unpublished", (person, kind) => { console.log("unpublished", person, kind); if (kind === "audio") { person.audioTrack?.cease(); } if (kind === "video") { setUsers((prevUsers) => { return prevUsers.filter((Consumer) => Consumer.uid !== person.uid); }); } }); consumer.on("user-left", (person) => { console.log("leaving", person); setUsers((prevUsers) => { return prevUsers.filter((Consumer) => Consumer.uid !== person.uid); }); }); await a part of(appId, title, token, null); if (tracks) await consumer.publish([tracks[0], tracks[1]]); setStart(true); }; if (prepared && tracks) { console.log("init prepared"); init(channelName); } }, [channelName, ready, tracks]); return ( <div className="App"> {prepared && tracks && <Controls tracks={tracks} setStart={setStart} setInCall={setInCall} />} {begin && tracks && <WebDashboard customers={customers} tracks={tracks} />} </div> ); };
export default VideoCall;

Utilizing the app ID and token that we obtained from, we will be a part of the channel when this element mounts.

We should publish the present person in order that others can subscribe and hearken to them and equally subscribe to incoming streams that different customers have already revealed.

Agora offers a number of occasions that we will hearken to and do the required actions required. For instance, each time a person leaves the channel, the user-left occasion will probably be triggered and we will hearken to it and take away that person from the stream.

We additionally retailer the person record, audio, and videoo that the video and audio might be streamed later for reference.

The ultimate half is making a element to point out all of the streams and controls to mute and unmute video and audio and go away the channel.

Be amazed exploring what sort of software you’ll be able to develop utilizing Syncfusion React elements.

Strive Now


There’s a set of strategies obtainable on supplied via the SDK that we will use to toggle the audio and video.

For leaving the channel, we should go away the consumer and shut the continued stream so that every one the opposite customers are notified that the person has left the channel.

Confer with the next code instance:


import React, { useState } from "react";
import useAgora from "./Hook";

const Controls = (props) => { const [useClient] = useAgora(); const consumer = useClient(); const { tracks, setStart, setInCall } = props; const [trackState, setTrackState] = useState({ video: true, audio: true }); const mute = async (kind) => { if (kind === "audio") { await tracks[0].setEnabled(!; setTrackState((ps) => { return {, audio: ! }; }); } else if (kind === "video") { await tracks[1].setEnabled(!; setTrackState((ps) => { return {, video: ! }; }); } }; const leaveChannel = async () => { await consumer.go away(); consumer.removeAllListeners(); tracks[0].shut(); tracks[1].shut(); setStart(false); setInCall(false); }; return ( <div className="controls"> <p className={ ? "on" : ""} onClick={() => mute("audio")}> { ? "MuteAudio" : "UnmuteAudio"} </p> <p className={ ? "on" : ""} onClick={() => mute("video")}> { ? "MuteVideo" : "UnmuteVideo"} </p> {<p onClick={() => leaveChannel()}>Depart</p>} </div> ); };
export default Controls;


For working the streams, we’re going to create a dashboard utilizing the Dashboad element supplied by Syncfusion. It’s a resizable, draggable, and versatile card with APIs which can be very user-friendly.

The present person stream will probably be proven on the high in a big dimension, whereas the opposite customers will probably be listed on the backside in smaller playing cards.

For this demo, I’ve created a number of empty person playing cards and I’ve joined the stream from two situations, one regular and one incognito.

All we should do is show the stream that we have now revealed (the present person) in a big dimension and show all of the incoming streams within the smaller playing cards.

Confer with the next code instance:

See the chances for your self with reside demos of Syncfusion React elements.

Strive Now


import React from "react";
import { AgoraVideoPlayer } from "agora-rtc-react";
import { DashboardLayoutComponent } from "@syncfusion/ej2-react-layouts";

import "@syncfusion/ej2-layouts/kinds/materials.css";
const WebDashboard = (props) => { const { customers, tracks } = props; const onPanelResize = (args) => { if ( args.factor && args.factor.querySelector(".e-panel-container .e-panel-content div div div") ) { let chartObj = args.factor.querySelector(".e-panel-container .e-panel-content div div div") .ej2_instances[0]; const peak = args.factor.querySelector(".e-panel-container .e-panel-content").clientHeight; chartObj.peak = `${peak - 20}`; chartObj.width = "100%"; chartObj.refresh();
} }; const dummy = new Array(customers.size < 6 ? 6 : customers.size).fill(0); return ( <div className="control-section" id="predefine_control"> <div className="content-wrapper" fashion={{ maxWidth: "95%", margin: "10px auto" }}> <DashboardLayoutComponent created={() => {}} columns={6} id="predefine_dashboard" cellSpacing={[5, 5]} resizeStop={onPanelResize} allowResizing={true} allowDragging={true} > <div id="one" className="e-panel" data-row="0" data-col="0" data-sizex="6" data-sizey="2"> <span id="shut" className="e-template-icon e-clear-icon" /> <div className="e-panel-container"> <AgoraVideoPlayer className="vid" videoTrack={tracks[1]} fashion={{ peak: "95%", width: "570px", margin: "8px auto" }} /> </div> </div> {, index) => ( <div id={`user-${index}`} className="e-panel" data-row="2" data-col={index} data-sizex="1" data-sizey="1" key={`user-${index}`} > <span id="shut" className="e-template-icon e-clear-icon" /> <div className="e-panel-container"> {customers[index]?.videoTrack && ( <AgoraVideoPlayer className="vid" videoTrack={customers[index].videoTrack} key={customers[index].uid} fashion={{ peak: "100%", width: "100%" }} /> )} </div> </div> ))} </DashboardLayoutComponent> </div> </div> ); };
export default WebDashboard;

That’s all there’s to it. The appliance is prepared. On working the applying, you’re going to get an output much like the next screenshot.

Video-Calling React App Created Using Agora and Syncfusion
Video-Calling React App Created Utilizing Agora and Syncfusion


For extra info, confer with the video-calling React software mission on GitHub.


I hope you discovered this weblog helpful. Strive creating your personal video-calling software in React utilizing Agora and Syncfusion React elements and share your suggestions within the remark part beneath.

The Syncfusion Important Studio for React suite affords over 80 high-performance, light-weight, modular, and responsive UI elements in a single bundle. It’s the one suite you’ll ever must assemble a whole app.

When you’ve got questions, contact us via our assist discussion boardassist portal, or suggestions portal. We’re at all times pleased to help you!

Associated blogs



Please enter your comment!
Please enter your name here

Most Popular

Recent Comments