UNPKG

get-set-react

Version:

A React State Management Library similar and alternative to mobx, redux.etc. it's the simplest, smallest and fastest state management library for react with dev tools support.

171 lines (158 loc) 4.5 kB
import { useCallback, useEffect, useMemo, useRef, useState as useReactState, useSyncExternalStore } from "react"; import { create as c, GetSet, createBubble as cb, BubbleType, ValType, MemoReturnType, createEffect as _createEffect, createMemo as _createMemo, atom as _atom, molecule as _molecule, } from "get-set-immutable"; export const create = c; export const useGet = <T extends Object, S extends Object = {}>( getSetInstance: GetSet<T, S> | BubbleType<T>, resetOnUnmount: boolean = false ): T & S => { const [state, setState] = useReactState(getSetInstance.getState()); useEffect(() => { const fn = () => { setState(getSetInstance.getState()); }; return getSetInstance.subscribe(fn); }, [setState]); useEffect(() => { return () => { resetOnUnmount && getSetInstance.reset(); }; }, []); //@ts-ignore return useMemo<T & S>(() => { return typeof state === "object" ? { ...state, //@ts-ignore ...(getSetInstance?.actions || {}), } : state; }, [state]); }; export const useVal = <T extends Object, S extends Object>( getSetInstance: GetSet<T, S>, resetOnUnmount: boolean = false ): ValType<T> & { actions?: S } => { const val: ValType<T> & { actions?: S } = useCallback( function ( newStateFn?: T | ((currentState: T) => void) | undefined, versionName?: string ) { if (arguments.length === 0) { return getSetInstance.val(); } else { return getSetInstance.val(newStateFn, versionName); } }, [getSetInstance.get()] ); val.actions = getSetInstance.actions; useGet(getSetInstance, resetOnUnmount); return val; }; export const useStore = <T extends Object, S extends Object = {}>( state: GetSet<T, S>, resetOnUnmount: boolean = false ): [state: T, actions: S | undefined] => { //@ts-ignore const s = useGet(state, resetOnUnmount); return [s, state.actions]; }; export function useVS<T extends Object>( initialState: T, key?: string ): ( newVal?: T | undefined | ((currentState: T) => void), versionName?: string ) => T { const state = useRef(create(initialState)); const _val = state.current.val; const [count, setCount] = useReactState(0); const update = () => { if (key) { setTimeout( () => viewStore.set((s: any) => ({ ...s, [key]: _val() })), 100 ); } }; const val = useCallback( // here props should be T | undefined | ((currentState: T) => T) function ( newState?: T | undefined | ((currentState: T) => void), versionName?: string ) { /// make it if else ///convert the below ternary to if else if (arguments.length > 0) { setCount(count + 1); return _val(newState, versionName); } else return _val(); }, [count] ); //update(); useOnlyOnce(update); useEffect(() => { let s = viewStore.get(); const unsub = state.current.subscribe(() => { setCount(count + 1); update(); }); return () => { unsub(); if (key && viewStore.get()?.[key]) { viewStore.update((s) => delete s[key]); } }; }, []); return val; } export const viewStore = create<any, any>({}); export const createBubble = cb; export function useReset<T extends Object, S extends Object = {}>( stateOrStore: (BubbleType<T> | GetSet<T, S>)[] ) { useEffect(() => { return stateOrStore.forEach((store) => store.reset); }, []); } export const useOnlyOnce = (fn: Function) => { const hasBeenUsed = useRef(false); if (hasBeenUsed.current === false) { fn(); hasBeenUsed.current = true; } }; export function useSelector< T extends Object, S extends Object | null | undefined >(getSetInstance: GetSet<T>, selectorFn: (state: T) => S) { const [state, setState] = useReactState(selectorFn(getSetInstance.getState())); useEffect(() => { const fn = () => { setState(selectorFn(getSetInstance.getState())); }; return getSetInstance.subscribe(fn); }, [setState]); return state; } export const useMemoValue = <T>(memo: MemoReturnType<T>) => { return useSyncExternalStore(memo.subscribe, memo.get); }; export const useState = <T extends Object>(initialState: T) => { const store = useRef(create(initialState)); return [useGet(store.current), store.current.val]; }; export const createEffect = _createEffect; export const createMemo = _createMemo; export const atom = _atom; export const molecule = _molecule;