From 110914a4d6c1767f65b5b4a45f1e16f7846999c6 Mon Sep 17 00:00:00 2001 From: Robin Date: Wed, 6 Nov 2024 04:43:27 -0500 Subject: [PATCH] Replace some custom React hooks with observable-hooks (#2710) The observable-hooks package provides hooks that do exactly the same thing as these custom React hooks I had written a while back. (even the names are the same, wow) Co-authored-by: Hugh Nimmo-Smith --- src/room/InCallView.tsx | 15 ++++++++++----- src/state/useObservable.ts | 34 ---------------------------------- src/tile/SpotlightTile.tsx | 5 ++--- 3 files changed, 12 insertions(+), 42 deletions(-) delete mode 100644 src/state/useObservable.ts diff --git a/src/room/InCallView.tsx b/src/room/InCallView.tsx index cd980234..bad58be3 100644 --- a/src/room/InCallView.tsx +++ b/src/room/InCallView.tsx @@ -28,8 +28,8 @@ import { import useMeasure from "react-use-measure"; import { MatrixRTCSession } from "matrix-js-sdk/src/matrixrtc/MatrixRTCSession"; import classNames from "classnames"; -import { BehaviorSubject } from "rxjs"; -import { useObservableEagerState } from "observable-hooks"; +import { BehaviorSubject, map } from "rxjs"; +import { useObservable, useObservableEagerState } from "observable-hooks"; import { logger } from "matrix-js-sdk/src/logger"; import LogoMark from "../icons/LogoMark.svg?react"; @@ -65,7 +65,6 @@ import { ECConnectionState } from "../livekit/useECConnectionState"; import { useOpenIDSFU } from "../livekit/openIDSFU"; import { CallViewModel, GridMode, Layout } from "../state/CallViewModel"; import { Grid, TileProps } from "../grid/Grid"; -import { useObservable } from "../state/useObservable"; import { useInitial } from "../useInitial"; import { SpotlightTile } from "../tile/SpotlightTile"; import { EncryptionSystem } from "../e2ee/sharedKeyManagement"; @@ -103,7 +102,10 @@ export const ActiveCall: FC = (props) => { sfuConfig, props.e2eeSystem, ); - const connStateObservable = useObservable(connState); + const connStateObservable = useObservable( + (inputs) => inputs.pipe(map(([connState]) => connState)), + [connState], + ); const [vm, setVm] = useState(null); useEffect(() => { @@ -308,7 +310,10 @@ export const InCallView: FC = ({ windowMode, ], ); - const gridBoundsObservable = useObservable(gridBounds); + const gridBoundsObservable = useObservable( + (inputs) => inputs.pipe(map(([gridBounds]) => gridBounds)), + [gridBounds], + ); const spotlightAlignment = useInitial( () => new BehaviorSubject(defaultSpotlightAlignment), diff --git a/src/state/useObservable.ts b/src/state/useObservable.ts deleted file mode 100644 index 0d53cf40..00000000 --- a/src/state/useObservable.ts +++ /dev/null @@ -1,34 +0,0 @@ -/* -Copyright 2023, 2024 New Vector Ltd. - -SPDX-License-Identifier: AGPL-3.0-only -Please see LICENSE in the repository root for full details. -*/ - -import { Ref, useCallback, useRef } from "react"; -import { BehaviorSubject, Observable } from "rxjs"; - -import { useInitial } from "../useInitial"; - -/** - * React hook that creates an Observable from a changing value. The Observable - * replays its current value upon subscription and emits whenever the value - * changes. - */ -export function useObservable(value: T): Observable { - const subject = useRef>(); - subject.current ??= new BehaviorSubject(value); - if (value !== subject.current.value) subject.current.next(value); - return subject.current; -} - -/** - * React hook that creates a ref and an Observable that emits any values - * stored in the ref. The Observable replays the value currently stored in the - * ref upon subscription. - */ -export function useObservableRef(initialValue: T): [Observable, Ref] { - const subject = useInitial(() => new BehaviorSubject(initialValue)); - const ref = useCallback((value: T) => subject.next(value), [subject]); - return [subject, ref]; -} diff --git a/src/tile/SpotlightTile.tsx b/src/tile/SpotlightTile.tsx index 6e1f0d85..64404567 100644 --- a/src/tile/SpotlightTile.tsx +++ b/src/tile/SpotlightTile.tsx @@ -22,7 +22,7 @@ import { } from "@vector-im/compound-design-tokens/assets/web/icons"; import { animated } from "@react-spring/web"; import { Observable, map } from "rxjs"; -import { useObservableEagerState } from "observable-hooks"; +import { useObservableEagerState, useObservableRef } from "observable-hooks"; import { useTranslation } from "react-i18next"; import classNames from "classnames"; import { TrackReferenceOrPlaceholder } from "@livekit/components-core"; @@ -39,7 +39,6 @@ import { } from "../state/MediaViewModel"; import { useInitial } from "../useInitial"; import { useMergedRefs } from "../useMergedRefs"; -import { useObservableRef } from "../state/useObservable"; import { useReactiveState } from "../useReactiveState"; import { useLatest } from "../useLatest"; import { SpotlightTileViewModel } from "../state/TileViewModel"; @@ -203,7 +202,7 @@ export const SpotlightTile = forwardRef( theirRef, ) => { const { t } = useTranslation(); - const [root, ourRef] = useObservableRef(null); + const [ourRef, root] = useObservableRef(null); const ref = useMergedRefs(ourRef, theirRef); const maximised = useObservableEagerState(vm.maximised); const media = useObservableEagerState(vm.media);