Skip to main content

ReactJS Classroom Workshop Tutorial

Build an interactive classroom with mediasfu-reactjs@4.3.0. The supplied room includes participants, messages, polls, breakouts, whiteboard, media, and exit.

Prerequisites

  • Node.js 18 to 20, React 18, HTTPS or localhost, and teacher/learner profiles.
  • Authenticated create/join routes with teacher and learner role policy.

Project files

package.json
{"private":true,"scripts":{"dev":"vite"},"dependencies":{"mediasfu-reactjs":"4.3.0","react":"18.2.0","react-dom":"18.2.0"},"devDependencies":{"@types/react":"18.3.24","@types/react-dom":"18.3.7","@vitejs/plugin-react":"4.3.4","typescript":"5.9.3","vite":"5.4.19"}}
src/App.tsx
import { ModernMediasfuGeneric, type CreateRoomOnMediaSFUType, type JoinRoomOnMediaSFUType } from 'mediasfu-reactjs';
async function postRoom<T>(url: string, payload: unknown): Promise<T> { const response = await fetch(url, { method: 'POST', credentials: 'same-origin', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) }); if (!response.ok) throw new Error(`Room request failed (HTTP ${response.status}).`); return response.json() as Promise<T>; }
const createRoom: CreateRoomOnMediaSFUType = ({ payload }) => postRoom('/api/mediasfu/create-room', payload); const joinRoom: JoinRoomOnMediaSFUType = ({ payload }) => postRoom('/api/mediasfu/join-room', payload);
export default function App() { return <main><header><h1>Classroom workshop</h1><p>Open Messages, Polls, Breakouts, or Whiteboard from the room.</p></header><ModernMediasfuGeneric connectMediaSFU={true} createMediaSFURoom={createRoom} joinMediaSFURoom={joinRoom} /></main>; }
src/main.tsx
import { StrictMode } from 'react'; import { createRoot } from 'react-dom/client'; import App from './App'; createRoot(document.getElementById('root')!).render(<StrictMode><App /></StrictMode>);
index.html
<!doctype html><html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width,initial-scale=1" /><title>Classroom workshop</title></head><body><div id="root"></div><script type="module" src="/src/main.tsx"></script></body></html>
vite.config.ts
import { defineConfig } from 'vite'; import react from '@vitejs/plugin-react'; export default defineConfig({ plugins: [react()] });
tsconfig.json
{"compilerOptions":{"target":"ES2022","lib":["DOM","ES2022"],"strict":true,"module":"ESNext","moduleResolution":"Bundler","skipLibCheck":true,"noEmit":true,"jsx":"react-jsx"},"include":["src"]}

For isolated local development, the backend may use restricted, revocable credentials that are never committed. Before distribution, external testing, or production rooms, reusable Cloud credentials must remain on the backend.

Backend

Implement the two API routes using the complete public production room credential boundary. The backend authorizes teacher and learner roles; the browser never receives a MediaSFU Cloud credential.

Run

npm install
npm run dev

Expected result

Teacher and learner join, exchange a message, complete a poll, enter and leave a breakout, and open/close the whiteboard according to room permissions.

Recovery

Keep a learner in the main room if a breakout move fails. Do not silently replay an interrupted poll or whiteboard action. Refresh current room state first.

Cleanup

End polls and breakouts, close whiteboard state, clear app-owned drafts, then use participant Leave or the authorized host End flow. Expire backend authority.