1import {useEffect, useState} from 'react'; 2 3export default class StateMapper<T> { 4 private getFun: () => T; 5 private cbs: Set<Function> = new Set([]); 6 constructor(getFun: () => T) { 7 this.getFun = getFun; 8 } 9 10 notify = () => { 11 this.cbs.forEach(_ => _?.()); 12 }; 13 14 useMappedState = () => { 15 const [_state, _setState] = useState<T>(this.getFun); 16 const updateState = () => { 17 _setState(this.getFun()); 18 }; 19 useEffect(() => { 20 this.cbs.add(updateState); 21 return () => { 22 this.cbs.delete(updateState); 23 }; 24 }, []); 25 return _state; 26 }; 27} 28 29type UpdateFunc<T> = (prev: T) => T; 30 31export class GlobalState<T> { 32 private value: T; 33 private stateMapper: StateMapper<T>; 34 35 constructor(initValue: T) { 36 this.value = initValue; 37 this.stateMapper = new StateMapper(this.getValue); 38 } 39 40 public getValue = () => { 41 return this.value; 42 }; 43 44 public useValue = () => { 45 return this.stateMapper.useMappedState(); 46 }; 47 48 public setValue = (value: T | UpdateFunc<T>) => { 49 let newValue: T; 50 if (typeof value === 'function') { 51 newValue = (value as UpdateFunc<T>)(this.value); 52 } else { 53 newValue = value; 54 } 55 56 this.value = newValue; 57 this.stateMapper.notify(); 58 }; 59} 60