Replace react-rxjs with observable-hooks

react-rxjs is the library we've been using to connect our React components to view models and consume observables. However, after spending some time with react-rxjs, I feel that it's a very heavy-handed solution. It requires us to sprinkle <Subscribe /> and <RemoveSubscribe /> components all throughout the code, and makes React go through an extra render cycle whenever we mount a component that binds to a view model. What I really want is a lightweight React hook that just gets the current value out of a plain observable, without any extra setup. Luckily the observable-hooks library with its useObservableEagerState hook seems to do just that—and it's more actively maintained, too!
This commit is contained in:
Robin
2024-05-16 15:23:10 -04:00
parent 0d485ef97f
commit af0bd795b5
9 changed files with 627 additions and 723 deletions

View File

@@ -14,16 +14,15 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import { CSSProperties, useMemo } from "react";
import { StateObservable, state, useStateObservable } from "@react-rxjs/core";
import { BehaviorSubject, distinctUntilChanged } from "rxjs";
import { CSSProperties, forwardRef, useMemo } from "react";
import { BehaviorSubject, Observable, distinctUntilChanged } from "rxjs";
import { useObservableEagerState } from "observable-hooks";
import { GridLayout as GridLayoutModel } from "../state/CallViewModel";
import { MediaViewModel } from "../state/MediaViewModel";
import { LayoutSystem, Slot } from "./Grid";
import styles from "./GridLayout.module.css";
import { useReactiveState } from "../useReactiveState";
import { subscribe } from "../state/subscribe";
import { Alignment } from "../room/InCallView";
import { useInitial } from "../useInitial";
@@ -48,7 +47,7 @@ const slotMaxAspectRatio = 17 / 9;
const slotMinAspectRatio = 4 / 3;
export const gridLayoutSystems = (
minBounds: StateObservable<Bounds>,
minBounds: Observable<Bounds>,
floatingAlignment: BehaviorSubject<Alignment>,
): GridLayoutSystems => ({
// The "fixed" (non-scrolling) part of the layout is where the spotlight tile
@@ -58,15 +57,13 @@ export const gridLayoutSystems = (
new Map(
model.spotlight === undefined ? [] : [["spotlight", model.spotlight]],
),
Layout: subscribe(function GridLayoutFixed({ model }, ref) {
const { width, height } = useStateObservable(minBounds);
const alignment = useStateObservable(
useInitial<StateObservable<Alignment>>(() =>
state(
floatingAlignment.pipe(
distinctUntilChanged(
(a1, a2) => a1.block === a2.block && a1.inline === a2.inline,
),
Layout: forwardRef(function GridLayoutFixed({ model }, ref) {
const { width, height } = useObservableEagerState(minBounds);
const alignment = useObservableEagerState(
useInitial(() =>
floatingAlignment.pipe(
distinctUntilChanged(
(a1, a2) => a1.block === a2.block && a1.inline === a2.inline,
),
),
),
@@ -106,8 +103,8 @@ export const gridLayoutSystems = (
// The scrolling part of the layout is where all the grid tiles live
scrolling: {
tiles: (model) => new Map(model.grid.map((tile) => [tile.id, tile])),
Layout: subscribe(function GridLayout({ model }, ref) {
const { width, height: minHeight } = useStateObservable(minBounds);
Layout: forwardRef(function GridLayout({ model }, ref) {
const { width, height: minHeight } = useObservableEagerState(minBounds);
// The goal here is to determine the grid size and padding that maximizes
// use of screen space for n tiles without making those tiles too small or