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
text/typescript
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;