From cc5279fc050636e50063b6d585032b7b20488f2a Mon Sep 17 00:00:00 2001 From: Robert Long <robert@robertlong.me> Date: Mon, 9 Aug 2021 13:54:23 -0700 Subject: [PATCH] Disallow joining multiple times and properly clean up event listeners --- src/ConferenceCallManagerHooks.js | 86 +++++++++++++++++-------------- src/Room.jsx | 16 ++++-- 2 files changed, 60 insertions(+), 42 deletions(-) diff --git a/src/ConferenceCallManagerHooks.js b/src/ConferenceCallManagerHooks.js index d123652..9d25452 100644 --- a/src/ConferenceCallManagerHooks.js +++ b/src/ConferenceCallManagerHooks.js @@ -131,15 +131,24 @@ export function useConferenceCallManager(homeserverUrl) { } export function useVideoRoom(manager, roomId, timeout = 5000) { - const [{ loading, joined, room, participants, error }, setState] = useState({ - loading: true, - joined: false, - room: undefined, - participants: [], - error: undefined, - }); + const [{ loading, joined, joining, room, participants, error }, setState] = + useState({ + loading: true, + joining: false, + joined: false, + room: undefined, + participants: [], + error: undefined, + }); useEffect(() => { + setState((prevState) => ({ + ...prevState, + loading: true, + room: undefined, + error: undefined, + })); + function onBeforeUnload(event) { manager.leaveCall(); } @@ -149,19 +158,14 @@ export function useVideoRoom(manager, roomId, timeout = 5000) { window.addEventListener(unloadEvent, onBeforeUnload); - return () => { - window.removeEventListener(unloadEvent, onBeforeUnload); - manager.leaveCall(); + const onParticipantsChanged = () => { + setState((prevState) => ({ + ...prevState, + participants: manager.participants, + })); }; - }, [manager]); - useEffect(() => { - setState((prevState) => ({ - ...prevState, - loading: true, - room: undefined, - error: undefined, - })); + manager.on("participants_changed", onParticipantsChanged); manager.client.joinRoom(roomId).catch((err) => { setState((prevState) => ({ ...prevState, loading: false, error: err })); @@ -208,47 +212,41 @@ export function useVideoRoom(manager, roomId, timeout = 5000) { return () => { manager.client.removeListener("Room", roomCallback); - manager.leaveCall(); + manager.removeListener("participants_changed", onParticipantsChanged); + window.removeEventListener(unloadEvent, onBeforeUnload); clearTimeout(timeoutId); + manager.leaveCall(); }; - }, [roomId]); + }, [manager, roomId]); const joinCall = useCallback(() => { - const onParticipantsChanged = () => { - setState((prevState) => ({ - ...prevState, - participants: manager.participants, - })); - }; + if (joining || joined) { + return; + } - manager.on("participants_changed", onParticipantsChanged); + setState((prevState) => ({ + ...prevState, + joining: true, + })); manager .enter(roomId) .then(() => { setState((prevState) => ({ ...prevState, + joining: false, joined: true, })); }) .catch((error) => { setState((prevState) => ({ ...prevState, + joining: false, joined: false, error, })); }); - - return () => { - manager.removeListener("participants_changed", onParticipantsChanged); - - setState((prevState) => ({ - ...prevState, - joined: false, - participants: [], - })); - }; - }, [manager, roomId]); + }, [manager, roomId, joining, joined]); const leaveCall = useCallback(() => { manager.leaveCall(); @@ -257,10 +255,20 @@ export function useVideoRoom(manager, roomId, timeout = 5000) { ...prevState, participants: manager.participants, joined: false, + joining: false, })); }, [manager]); - return { loading, joined, room, participants, error, joinCall, leaveCall }; + return { + loading, + joined, + joining, + room, + participants, + error, + joinCall, + leaveCall, + }; } export function useRooms(manager) { diff --git a/src/Room.jsx b/src/Room.jsx index 47204dd..12075d4 100644 --- a/src/Room.jsx +++ b/src/Room.jsx @@ -28,8 +28,16 @@ function useQuery() { export function Room({ manager }) { const { roomId } = useParams(); const query = useQuery(); - const { loading, joined, room, participants, error, joinCall, leaveCall } = - useVideoRoom(manager, roomId); + const { + loading, + joined, + joining, + room, + participants, + error, + joinCall, + leaveCall, + } = useVideoRoom(manager, roomId); const debugStr = query.get("debug"); const [debug, setDebug] = useState(debugStr === "" || debugStr === "true"); @@ -77,7 +85,9 @@ export function Room({ manager }) { <li key={member.userId}>{member.name}</li> ))} </ul> - <button onClick={joinCall}>Join Call</button> + <button disabled={joining} onClick={joinCall}> + Join Call + </button> </div> )} {!loading && room && joined && participants.length === 0 && (