react-hooks-global-states
Version:
This is a package to easily handling global-state across your react-components using hooks.
153 lines (152 loc) • 7.55 kB
TypeScript
export type StateSetter<State> = (setter: State | ((state: State) => State), meta?: {
/**
* @description you can add an identifier to the state call
* this will show up in the devtools to help you identify from where the state change was called
*/
identifier?: string | undefined;
/**
* @deprecated forceUpdate normally should not be used inside components
* Use this flag just in custom implementations of the global store
*/
forceUpdate?: boolean | undefined;
}) => void;
export type HookExtensions<State, StateMutator, Metadata extends BaseMetadata | unknown> = {
/**
* @description Return the state controls of the hook
* This selectors includes:
* - stateRetriever: a function to get the current state or subscribe a callback to the state changes
* - stateMutator: a function to set the state or a collection of actions if you pass an storeActionsConfig configuration
* - metadataRetriever: a function to get the metadata of the global state
*/
stateControls: () => Readonly<[
retriever: StateGetter<State>,
mutator: StateMutator,
metadata: MetadataGetter<Metadata>
]>;
/***
* @description Creates a new hooks that returns the result of the selector passed as a parameter
* Your can create selector hooks of other selectors hooks and extract as many derived states as or fragments of the state as you want
* The selector hook will be evaluated only if the result of the selector changes and the equality function returns false
* you can customize the equality function by passing the isEqualRoot and isEqual parameters
*/
createSelectorHook: <Derivate>(this: StateHook<State, StateMutator, Metadata>, selector: (state: State) => Derivate, args?: Omit<UseHookConfig<Derivate, State>, 'dependencies'> & {
name?: string;
}) => StateHook<Derivate, StateMutator, Metadata>;
createObservable: <Fragment>(this: StateHook<State, StateMutator, Metadata>, mainSelector: (state: State) => Fragment, args?: {
isEqual?: (current: Fragment, next: Fragment) => boolean;
isEqualRoot?: (current: State, next: State) => boolean;
name?: string;
}) => ObservableFragment<Fragment>;
removeSubscriptions: () => void;
dispose: () => void;
};
export type ObservableFragment<State> = StateGetter<State> & {
createObservable: <Fragment>(this: ObservableFragment<State>, mainSelector: (state: State) => Fragment, args?: {
isEqual?: (current: Fragment, next: Fragment) => boolean;
isEqualRoot?: (current: State, next: State) => boolean;
name?: string;
}) => ObservableFragment<Fragment>;
removeSubscriptions: () => void;
_name: string | undefined;
};
export interface StateHook<State, StateMutator, Metadata extends BaseMetadata | unknown> extends HookExtensions<State, StateMutator, Metadata> {
(): Readonly<[state: State, stateMutator: StateMutator, metadata: Metadata]>;
<Derivate>(selector: (state: State) => Derivate, dependencies?: unknown[]): Readonly<[
state: Derivate,
stateMutator: StateMutator,
metadata: Metadata
]>;
<Derivate>(selector: (state: State) => Derivate, config?: UseHookConfig<Derivate, State>): Readonly<[
state: Derivate,
stateMutator: StateMutator,
metadata: Metadata
]>;
}
export type MetadataSetter<Metadata extends BaseMetadata | unknown> = (setter: Metadata | ((metadata: Metadata) => Metadata)) => void;
export type StateChanges<State> = {
state: State;
previousState: State | undefined;
identifier: string | undefined;
};
/**
* API for the actions of the global states
**/
export type StoreTools<State, Metadata extends BaseMetadata | unknown = BaseMetadata, Actions extends undefined | unknown | Record<string, (...args: any[]) => any> = unknown> = {
setMetadata: MetadataSetter<Metadata>;
setState: StateSetter<State>;
getState: StateGetter<State>;
getMetadata: () => Metadata;
actions: Actions;
};
/**
* contract for the storeActionsConfig configuration
*/
export interface ActionCollectionConfig<State, Metadata extends BaseMetadata | unknown, ThisAPI = Record<string, (...parameters: any[]) => unknown>> {
readonly [key: string]: {
(this: ThisAPI, ...parameters: any[]): (this: ThisAPI, storeTools: StoreTools<State, Metadata, Record<string, (...parameters: any[]) => unknown | void>>) => unknown | void;
};
}
export type ActionCollectionResult<State, Metadata extends BaseMetadata | unknown, ActionsConfig extends ActionCollectionConfig<State, Metadata>> = {
[key in keyof ActionsConfig]: {
(...params: Parameters<ActionsConfig[key]>): ReturnType<ReturnType<ActionsConfig[key]>>;
};
};
export type GlobalStoreCallbacks<State, Metadata extends BaseMetadata | unknown> = {
onInit?: (args: StoreTools<State, Metadata>) => void;
onStateChanged?: (args: StoreTools<State, Metadata> & StateChanges<State>) => void;
onSubscribed?: (args: StoreTools<State, Metadata>) => void;
computePreventStateChange?: (args: StoreTools<State, Metadata> & StateChanges<State>) => boolean;
};
export type UseHookConfig<State, TRoot = any> = {
isEqual?: (current: State, next: State) => boolean;
isEqualRoot?: (current: TRoot, next: TRoot) => boolean;
dependencies?: unknown[];
};
export type UnsubscribeCallback = () => void;
export type SubscribeCallbackConfig<State> = UseHookConfig<State> & {
/**
* By default the callback is executed immediately after the subscription
*/
skipFirst?: boolean;
};
/**
* Callback function to subscribe to the store changes
*/
export type SubscribeCallback<State> = (state: State) => void;
/**
* get the current state or subscribe to the state changes
*/
export type StateGetter<State> = {
(): State;
(subscription: SubscribeCallback<State>, config?: SubscribeCallbackConfig<State>): UnsubscribeCallback;
<TDerivate>(selector: SelectorCallback<State, TDerivate>, subscription: SubscribeCallback<TDerivate>, config?: SubscribeCallbackConfig<TDerivate>): UnsubscribeCallback;
};
export type BaseMetadata = Record<string, unknown>;
export type MetadataGetter<Metadata extends BaseMetadata | unknown> = () => Metadata;
export type CustomGlobalHookBuilderParams<TCustomConfig extends BaseMetadata | unknown, Metadata extends BaseMetadata | unknown> = {
onInitialize?: (args: StoreTools<unknown, Metadata, unknown>, config: TCustomConfig | undefined) => void;
onChange?: (args: StoreTools<unknown, Metadata, unknown> & StateChanges<unknown>, config: TCustomConfig | undefined) => void;
};
export type SelectorCallback<State, TDerivate> = (state: State) => TDerivate;
export type SubscriberParameters = {
subscriptionId: string;
selector: SelectorCallback<unknown, unknown> | undefined;
config: UseHookConfig<unknown> | SubscribeCallbackConfig<unknown> | undefined;
currentState: unknown;
callback: SubscriptionCallback | React.Dispatch<React.SetStateAction<{
state: unknown;
}>>;
isSetStateCallback: boolean;
};
/**
* @description
* This is the final listener of the store changes, it can be a subscription or a setState
* @param {unknown} params - The parameters of the subscription
* @param {unknown} params.state - The new state
* @param {string} params.identifier - Optional identifier for the setState call
*/
export type SubscriptionCallback<State = unknown> = (params: {
state: State;
}, args: {
identifier?: string;
}) => void;