Skip to content

Commit

Permalink
Change useStateStore to use useSyncExternalStore instead
Browse files Browse the repository at this point in the history
  • Loading branch information
arnautov-anton committed Dec 6, 2024
1 parent 0577ffd commit d9b6440
Showing 1 changed file with 25 additions and 9 deletions.
34 changes: 25 additions & 9 deletions src/store/hooks/useStateStore.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { useEffect, useState } from 'react';
import { useCallback, useMemo, useSyncExternalStore } from 'react';

import type { StateStore } from 'stream-chat';

// eslint-disable-next-line @typescript-eslint/no-empty-function
const noop = () => {};

export function useStateStore<
T extends Record<string, unknown>,
O extends Readonly<Record<string, unknown> | Readonly<unknown[]>>
Expand All @@ -14,18 +17,31 @@ export function useStateStore<
T extends Record<string, unknown>,
O extends Readonly<Record<string, unknown> | Readonly<unknown[]>>
>(store: StateStore<T> | undefined, selector: (v: T) => O) {
const [state, setState] = useState<O | undefined>(() => {
if (!store) return undefined;
return selector(store.getLatestValue());
});
const wrappedSubscription = useCallback(
(onStoreChange: (a: O) => void) => {
const unsubscribe = store?.subscribeWithSelector(selector, onStoreChange);
return unsubscribe ?? noop;
},
[store, selector],
);

const wrappedSnapshot = useMemo(() => {
let cached: [T, O];
return () => {
const current = store?.getLatestValue();

useEffect(() => {
if (!store) return;
if (!current) return undefined;

const unsubscribe = store.subscribeWithSelector(selector, setState);
if (!cached || cached[0] !== current) {
cached = [current, selector(current)];
return cached[1];
}

return unsubscribe;
return cached[1];
};
}, [store, selector]);

const state = useSyncExternalStore(wrappedSubscription, wrappedSnapshot);

return state;
}

0 comments on commit d9b6440

Please sign in to comment.