diff --git a/packages/react/src/useComponentValue.ts b/packages/react/src/useComponentValue.ts index 63c8beb967..3b9430b5cc 100644 --- a/packages/react/src/useComponentValue.ts +++ b/packages/react/src/useComponentValue.ts @@ -1,5 +1,6 @@ import { Component, + ComponentUpdate, ComponentValue, defineQuery, Entity, @@ -7,8 +8,10 @@ import { Has, isComponentUpdate, Schema, + UpdateType, } from "@latticexyz/recs"; import { useEffect, useState } from "react"; +import { debounceTime, filter } from "rxjs"; export function useComponentValue( component: Component, @@ -34,12 +37,18 @@ export function useComponentValue( if (entity == null) return; const queryResult = defineQuery([Has(component)], { runOnInit: false }); - const subscription = queryResult.update$.subscribe((update) => { - if (isComponentUpdate(update, component) && update.entity === entity) { + const subscription = queryResult.update$ + .pipe( + filter( + (update): update is ComponentUpdate & { type: UpdateType } => + isComponentUpdate(update, component) && update.entity === entity + ), + debounceTime(10) + ) + .subscribe((update) => { const [nextValue] = update.value; setValue(nextValue); - } - }); + }); return () => subscription.unsubscribe(); }, [component, entity]); diff --git a/packages/react/src/useEntityQuery.ts b/packages/react/src/useEntityQuery.ts index f04d7d91a2..b6a54f5a75 100644 --- a/packages/react/src/useEntityQuery.ts +++ b/packages/react/src/useEntityQuery.ts @@ -2,7 +2,7 @@ import { defineQuery, QueryFragment } from "@latticexyz/recs"; import { useEffect, useMemo, useState } from "react"; import { useDeepMemo } from "./utils/useDeepMemo"; import isEqual from "fast-deep-equal"; -import { distinctUntilChanged, map } from "rxjs"; +import { debounceTime, distinctUntilChanged, map } from "rxjs"; // This does a little more rendering than is necessary when arguments change, // but at least it's giving correct results now. Will optimize later! @@ -29,7 +29,7 @@ export function useEntityQuery(fragments: QueryFragment[], options?: { updateOnV // re-render only on entity array changes observable = observable.pipe(distinctUntilChanged((a, b) => isEqual(a, b))); } - const subscription = observable.subscribe((entities) => setEntities(entities)); + const subscription = observable.pipe(debounceTime(10)).subscribe((entities) => setEntities(entities)); return () => subscription.unsubscribe(); }, [query, updateOnValueChange]); diff --git a/packages/recs/src/System.ts b/packages/recs/src/System.ts index eaf8d2b2a0..d655aea39f 100644 --- a/packages/recs/src/System.ts +++ b/packages/recs/src/System.ts @@ -1,4 +1,4 @@ -import { concat, EMPTY, from, Observable } from "rxjs"; +import { concat, debounceTime, EMPTY, from, Observable } from "rxjs"; import { getComponentEntities, removeComponent, setComponent } from "./Component"; import { UpdateType } from "./constants"; import { defineEnterQuery, defineExitQuery, defineQuery, defineUpdateQuery } from "./Query"; @@ -17,7 +17,7 @@ import { toUpdateStream } from "./utils"; * @param system System function to run on updates of the `observable$`. System function gets passed the update events from the `observable$`. */ export function defineRxSystem(world: World, observable$: Observable, system: (event: T) => void) { - const subscription = observable$.subscribe(system); + const subscription = observable$.pipe(debounceTime(10)).subscribe(system); world.registerDisposer(() => subscription?.unsubscribe()); }