mirror of
https://github.com/vector-im/element-call.git
synced 2026-09-10 21:55:19 +00:00
End the component's media device scope on unmount
The component built its `MediaDevices` once, in a scope nothing ever ended, so every mount left device observers running for the rest of the page's life. Building it in an effect ties the scope to the component's lifetime — and to the options it was built with, which were previously frozen at first render. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
a010cc983f
commit
608f107f8d
+48
-31
@@ -32,7 +32,14 @@ Please see LICENSE in the repository root for full details.
|
|||||||
// sits in a `@layer`, which loses to unlayered rules either way.
|
// sits in a `@layer`, which loses to unlayered rules either way.
|
||||||
import "../src/base.css";
|
import "../src/base.css";
|
||||||
|
|
||||||
import { type FC, type JSX, type ReactNode, useMemo, useState } from "react";
|
import {
|
||||||
|
type FC,
|
||||||
|
type JSX,
|
||||||
|
type ReactNode,
|
||||||
|
useEffect,
|
||||||
|
useMemo,
|
||||||
|
useState,
|
||||||
|
} from "react";
|
||||||
import { type MatrixClient } from "matrix-js-sdk";
|
import { type MatrixClient } from "matrix-js-sdk";
|
||||||
import { logger } from "matrix-js-sdk/lib/logger";
|
import { logger } from "matrix-js-sdk/lib/logger";
|
||||||
import { MemoryRouter } from "react-router-dom";
|
import { MemoryRouter } from "react-router-dom";
|
||||||
@@ -65,7 +72,6 @@ import { Config } from "../src/config/Config";
|
|||||||
import { type ConfigOptions } from "../src/config/ConfigOptions";
|
import { type ConfigOptions } from "../src/config/ConfigOptions";
|
||||||
import { i18n } from "../src/utils/i18n";
|
import { i18n } from "../src/utils/i18n";
|
||||||
import { useTheme } from "../src/useTheme";
|
import { useTheme } from "../src/useTheme";
|
||||||
import { useInitial } from "../src/useInitial";
|
|
||||||
import { useStableValue } from "../src/useStableValue";
|
import { useStableValue } from "../src/useStableValue";
|
||||||
import styles from "./ElementCall.module.css";
|
import styles from "./ElementCall.module.css";
|
||||||
|
|
||||||
@@ -200,13 +206,22 @@ export const ElementCall: FC<ElementCallProps> = ({
|
|||||||
[roomId, intent, stableConfig],
|
[roomId, intent, stableConfig],
|
||||||
);
|
);
|
||||||
|
|
||||||
const mediaDevices = useInitial(
|
// Created in an effect so that the scope it lives in ends when the component
|
||||||
() =>
|
// is unmounted (or these options change), rather than keeping its device
|
||||||
new MediaDevices(new ObservableScope(), {
|
// observers running for the rest of the page's life. Null until then, which
|
||||||
controlledAudioDevices: params.controlledAudioDevices,
|
// is one render.
|
||||||
callIntent: params.callIntent,
|
const { controlledAudioDevices, callIntent } = params;
|
||||||
}),
|
const [mediaDevices, setMediaDevices] = useState<MediaDevices | null>(null);
|
||||||
);
|
useEffect(() => {
|
||||||
|
const scope = new ObservableScope();
|
||||||
|
setMediaDevices(
|
||||||
|
new MediaDevices(scope, { controlledAudioDevices, callIntent }),
|
||||||
|
);
|
||||||
|
return (): void => {
|
||||||
|
setMediaDevices(null);
|
||||||
|
scope.end();
|
||||||
|
};
|
||||||
|
}, [controlledAudioDevices, callIntent]);
|
||||||
|
|
||||||
const room = client.getRoom(roomId);
|
const room = client.getRoom(roomId);
|
||||||
const rtcSession = useMemo(
|
const rtcSession = useMemo(
|
||||||
@@ -227,28 +242,30 @@ export const ElementCall: FC<ElementCallProps> = ({
|
|||||||
embedded cannot disturb the host's URL. */}
|
embedded cannot disturb the host's URL. */}
|
||||||
<MemoryRouter>
|
<MemoryRouter>
|
||||||
<div ref={setContainer} className={styles.root}>
|
<div ref={setContainer} className={styles.root}>
|
||||||
{container !== null && rtcSession !== null && (
|
{container !== null &&
|
||||||
<RootElementProvider value={container}>
|
rtcSession !== null &&
|
||||||
<Decoration>
|
mediaDevices !== null && (
|
||||||
<TooltipProvider>
|
<RootElementProvider value={container}>
|
||||||
<ClientProvider client={client}>
|
<Decoration>
|
||||||
<MediaDevicesContext value={mediaDevices}>
|
<TooltipProvider>
|
||||||
<ProcessorProvider>
|
<ClientProvider client={client}>
|
||||||
<ElementCallView
|
<MediaDevicesContext value={mediaDevices}>
|
||||||
client={client}
|
<ProcessorProvider>
|
||||||
rtcSession={rtcSession}
|
<ElementCallView
|
||||||
isPasswordlessUser={false}
|
client={client}
|
||||||
confineToRoom={params.confineToRoom}
|
rtcSession={rtcSession}
|
||||||
preload={params.preload}
|
isPasswordlessUser={false}
|
||||||
skipLobby={params.skipLobby}
|
confineToRoom={params.confineToRoom}
|
||||||
/>
|
preload={params.preload}
|
||||||
</ProcessorProvider>
|
skipLobby={params.skipLobby}
|
||||||
</MediaDevicesContext>
|
/>
|
||||||
</ClientProvider>
|
</ProcessorProvider>
|
||||||
</TooltipProvider>
|
</MediaDevicesContext>
|
||||||
</Decoration>
|
</ClientProvider>
|
||||||
</RootElementProvider>
|
</TooltipProvider>
|
||||||
)}
|
</Decoration>
|
||||||
|
</RootElementProvider>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</MemoryRouter>
|
</MemoryRouter>
|
||||||
</UrlParamsProvider>
|
</UrlParamsProvider>
|
||||||
|
|||||||
Reference in New Issue
Block a user