Skip to content

Instantly share code, notes, and snippets.

@vlas-ilya
Created July 19, 2021 18:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save vlas-ilya/c4348a0cdea882f748ac6f3f627f900c to your computer and use it in GitHub Desktop.
Save vlas-ilya/c4348a0cdea882f748ac6f3f627f900c to your computer and use it in GitHub Desktop.
React hook for sharing state between components
import { useEffect, useMemo, useRef, useState } from "react";
interface State<T> {
state: T;
setState: (state: T) => void;
handlers: ((state: T) => void) [];
}
interface GlobalState {
[key: string]: State<any>;
}
const globalState: GlobalState = {
};
export function useSharedState<T>(name: string, initState: T): [T, (state: T) => void] {
const initGlobalState = useMemo<State<T>>(() => ({
state: initState,
setState: () => {},
handlers: [],
}), [initState]);
const [state, setState] = useState<State<T>>(initGlobalState);
const oldSetState = useRef<(value: State<T>) => void>(setState);
useEffect(() => {
globalState[name] = globalState[name] || {
state: initState,
setState: state => {
globalState[name] = { ...globalState[name], state };
globalState[name].handlers.forEach(handler => handler(globalState[name]));
},
handlers: []
}
setState(globalState[name]);
return () => {
globalState[name].handlers = [...globalState[name].handlers.filter(item => item !== oldSetState.current)]
if (globalState[name].handlers.length === 0) {
delete globalState[name];
}
}
}, [initState, name]);
useEffect(() => {
if (globalState[name]) {
globalState[name].handlers = [setState, ...globalState[name].handlers.filter(item => item !== oldSetState.current)];
oldSetState.current = setState;
}
}, [name, setState]);
return [state.state, state.setState];
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment