Skip to content

Instantly share code, notes, and snippets.

@erodactyl
Last active August 1, 2022 14:46
Show Gist options
  • Save erodactyl/ebc2c8d28d971968c6ae5cb7f71a9a76 to your computer and use it in GitHub Desktop.
Save erodactyl/ebc2c8d28d971968c6ae5cb7f71a9a76 to your computer and use it in GitHub Desktop.
import { useEffect, useReducer, useMemo } from "react";
import { BehaviorSubject } from "rxjs";
export const createStateHook = <S>(init: S) => {
const state$ = new BehaviorSubject(init);
const setState = (change: S | ((state: S) => S)) => {
state$.next(change instanceof Function ? change(state$.value) : change);
};
return (): [S, typeof setState] => {
const [, forceUpdate] = useReducer((s) => s + 1, 0);
useEffect(() => {
const subscription = state$.subscribe(forceUpdate);
return () => subscription.unsubscribe();
}, []);
return [state$.value, setState];
};
};
// For usage with multiples, like chat rooms message drafts
export const createStateHooks = <S>(init: S) => {
const states = new Map<string, BehaviorSubject<S>>();
const getState = (id: string) => {
if (!states.has(id)) {
states.set(id, new BehaviorSubject(init));
}
return states.get(id)!;
};
const createSetState = (id: string) => (change: S | ((state: S) => S)) => {
const state$ = getState(id);
state$.next(change instanceof Function ? change(state$.value) : change);
};
return (id: string): [S, (c: S | ((s: S) => S)) => void] => {
const state$ = getState(id);
const [, forceUpdate] = useReducer((s) => s + 1, 0);
const setState = useMemo(() => createSetState(id), [id]);
useEffect(() => {
const subscription = state$.subscribe(forceUpdate);
return () => subscription.unsubscribe();
}, [id]);
return [state$.value, setState];
};
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment