Skip to content

Instantly share code, notes, and snippets.

@101arrowz
Last active December 17, 2020 17:49
Show Gist options
  • Save 101arrowz/0964129f4b24f224b278defc2a654c65 to your computer and use it in GitHub Desktop.
Save 101arrowz/0964129f4b24f224b278defc2a654c65 to your computer and use it in GitHub Desktop.
Shared React state
import { useEffect, useState } from 'react';
type Subscribable<T> = {
trigger(newValue: T): void;
subscribe(listener: (value: T) => unknown): number;
unsubscribe(ind: number): void;
};
const createSubscribable = <T = void>(): Subscribable<T> => {
const subs: ((value: T) => unknown)[] = [];
const trigger = (value: T) => {
for (const sub of subs) {
sub(value);
}
};
const subscribe = (listener: (value: T) => unknown) => {
return subs.push(listener) - 1;
}
const unsubscribe = (ind: number) => {
subs.splice(ind, 1);
}
return {
trigger,
subscribe,
unsubscribe
};
}
const createHook = <T = void>(initialState: T, key?: string) => {
const subscribable = createSubscribable<T>();
if (key) {
const lsKey = 'react-store-' + key;
const rehydrated = localStorage.getItem(lsKey);
if (rehydrated) initialState = JSON.parse(rehydrated);
subscribable.subscribe(newState => {
// beforeunload event is reliable but can fail during a crash, so persist
// on update.
localStorage.setItem(lsKey, JSON.stringify(newState));
});
}
const useSubscription = () => {
const [state, setState] = useState<T>(initialState);
useEffect(() => {
const id = subscribable.subscribe(setState);
return () => subscribable.unsubscribe(id);
}, [setState]);
return [state, (newState: T) => {
subscribable.trigger(newState);
}];
}
return useSubscription;
}
// For example:
// const useSidebarOpen = createHook(false);
// const useFirstLogin = createHook(false, 'firstLogin');
// These can be used as if it were useState but with no parameters
// Whenever one component calls setState from the hook, all subscribers receive
// the update
// useFirstLogin will automatically persist to and rehydrate from localStorage
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment