Created
January 13, 2020 00:06
-
-
Save hunteva/6e41f018264e2103b529353a814e309d to your computer and use it in GitHub Desktop.
A Tiny Global State hooks provide immutability via session-storage and strong type check against StateShape
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { useState, useEffect, useRef } from 'react'; | |
import { getState, setState } from './session-storage'; | |
import { StateShape } from './types'; | |
type StateKey = keyof StateShape; | |
const TriggersMap = new Map<StateKey, Set<Function>>(); | |
const triggerRenderById = (id: StateKey) => { | |
const triggers = TriggersMap.get(id) || new Set([]); | |
triggers.forEach(trigger => trigger(Date.now())); | |
}; | |
const setupTriggers = (id: StateKey, trigger: (_: any) => void): (() => void) => { | |
const triggers = TriggersMap.get(id) || new Set(); | |
triggers.add(trigger); | |
TriggersMap.set(id, triggers); | |
return () => triggers.delete(trigger); | |
}; | |
export const useGlobalState = <K extends StateKey>( | |
id: K, | |
initValue: StateShape[K] | undefined | |
): [StateShape[K] | undefined, (payload: StateShape[K]) => void] => { | |
const [_, trigger] = useState(id); | |
const ref = useRef({ firstRender: true, compId: id }); | |
const { firstRender, compId } = ref.current; | |
if (compId !== id) { | |
throw new Error("id should not change during component's life cycle"); | |
} | |
useEffect(() => { | |
setState(id, initValue); | |
ref.current.firstRender = false; | |
return setupTriggers(id, trigger); | |
// eslint-disable-next-line react-hooks/exhaustive-deps | |
}, []); | |
const curValue = !firstRender ? getState<StateShape[K]>(id) : initValue; | |
return [ | |
curValue as StateShape[K], | |
(value: StateShape[K]) => { | |
setState(id, value); | |
triggerRenderById(id); | |
} | |
]; | |
}; | |
export const watchGlobalState = <K extends StateKey>(id: K): StateShape[K] | undefined => { | |
const [_, trigger] = useState(id); | |
useEffect(() => setupTriggers(id, trigger), [id]); | |
return getState<StateShape[K]>(id); | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment