UNPKG

react-native-global-state-hooks

Version:

This is a package to easily handling global-state across your react-native-components No-redux... The library now includes @react-native-async-storage/async-storage to persist your state across sessions... if you want to keep using the old version without

202 lines (201 loc) 8.26 kB
export type { StateApi, AnyFunction, StateChanges, UseHookOptions, UnsubscribeCallback, SubscribeCallbackConfig, SubscribeCallback, SelectorCallback, SubscriberParameters, SubscriptionCallback, } from "react-hooks-global-states/types"; import React from "react"; import type { BaseMetadata as BaseLibraryMetadata, StateApi, StateChanges, SubscriberParameters, UseHookOptions } from "react-hooks-global-states"; import { AnyFunction, SubscribeToState } from "react-hooks-global-states/types"; export type AsyncStorageConfig<State> = { /** * @description The key used to store the item in async storage. */ key: string; /** * @description Validator function to ensure the integrity of the restored state. * Receives the restored value and the initial state... If the function returns a value then * that value is used as the new state. If it returns `void` (undefined) then the restored state is used * and the async storage is updated accordingly. * * Executes after every initialization from async storage, including after migration. * * @example * ```ts * validator: ({ restored, initial }) => { * if (typeof restored !== 'number') { * return initial; * } * * return restored; * } * ``` */ validator: (args: { restored: unknown; initial: any; }) => any | void; /** * @description Error callback invoked when an exception occurs during any persistence phase. * Use this to log or report issues without throwing. */ onError?: (error: unknown) => void; versioning?: { /** * @description Current schema version for this item. When the stored version differs, * the `migrator` function is invoked to upgrade the stored value. * @default -1 * @example * ```ts * { * key: 'counter', * version: 1 * } * ``` */ version: string | number; /** * @description Called when a stored value is found with a different version. * Receives the raw stored value and must return the upgraded `State`. * If and error is thrown during migration, the `onError` callback is invoked * and the state falls back to the initial value. */ migrator: (args: { legacy: unknown; initial: any; }) => any; }; /** * @description High level overrides of the async storage synchronization * Use it if you want to have full control of how the state is stored/retrieved. * * This disables versioning, migration */ adapter?: { /** * @description Custom setter for the stored value associated with `key`. */ setItem: (key: string, value: State) => Promise<void>; /** * @description Custom getter for the stored value associated with `key`. * Should return the previously stored value (parsed/decoded to `State`) for that key. */ getItem: (key: string) => Promise<State | null>; }; }; /** * @description Structure of the item stored in async storage */ export type ItemEnvelope<T> = { /** * @description Actual stored state */ s: T; /** * @description Version of the stored state */ v?: string | number; }; export type BaseMetadata = BaseLibraryMetadata & { isAsyncStorageReady?: boolean; asyncStorageKey?: string | null; }; /** * The base metadata for async storage always carries the information about the async storage state and * the key used to store the state in async storage. */ export type AsyncMetadata<T> = (keyof T extends never ? {} : T) & BaseMetadata; export interface StateHook<State, StateMutator, Metadata extends BaseMetadata> extends StateApi<State, StateMutator, Metadata> { /** * @description React hook that provides access to the state, state mutator, and metadata. */ (): Readonly<[state: State, stateMutator: StateMutator, metadata: Metadata]>; /** * @description React hook that provides a derived state based on the provided selector function. */ <Derivate>(selector: (state: State) => Derivate, dependencies?: unknown[]): Readonly<[state: Derivate, stateMutator: StateMutator, metadata: Metadata]>; /** * @description React hook that provides a derived state based on the provided selector function and configuration. */ <Derivate>(selector: (state: State) => Derivate, config?: UseHookOptions<Derivate, State>): Readonly<[state: Derivate, stateMutator: StateMutator, metadata: Metadata]>; } export type MetadataSetter<Metadata extends BaseMetadata> = (setter: Metadata | ((metadata: Metadata) => Metadata)) => void; /** * API for the actions of the global states **/ export type StoreTools<State, StateMutator = React.Dispatch<React.SetStateAction<State>>, Metadata extends BaseMetadata = BaseMetadata> = { /** * The actions available for the global state */ actions: StateMutator extends AnyFunction ? null : StateMutator; /** * @description Metadata associated with the global state */ getMetadata: () => Metadata; /** * @description Current state value */ getState: () => State; /** * @description Sets the metadata value */ setMetadata: MetadataSetter<Metadata>; /** * @description Function to set the state value */ setState: React.Dispatch<React.SetStateAction<State>>; /** * @description Subscribe to the state changes * You can subscribe to the whole state or to a fragment of the state by passing a selector as first parameter, * this can be used in non react environments to listen to the state changes * * @example * ```ts * const unsubscribe = storeTools.subscribe((state) => { * console.log('State changed:', state); * }); * * // To unsubscribe later * unsubscribe(); * ``` */ subscribe: SubscribeToState<State>; }; /** * contract for the storeActionsConfig configuration */ export interface ActionCollectionConfig<State, Metadata extends BaseMetadata, ThisAPI = Record<string, (...parameters: any[]) => unknown>> { readonly [key: string]: { (this: ThisAPI, ...parameters: any[]): (this: ThisAPI, storeTools: StoreTools<State, Record<string, (...parameters: any[]) => unknown | void>, Metadata>) => unknown | void; }; } /** * @description Resulting type of the action collection configuration */ export type ActionCollectionResult<State, Metadata extends BaseMetadata, ActionsConfig extends ActionCollectionConfig<State, Metadata>> = { [key in keyof ActionsConfig]: { (...params: Parameters<ActionsConfig[key]>): ReturnType<ReturnType<ActionsConfig[key]>>; }; }; /** * Callbacks for the global store lifecycle events */ export type GlobalStoreCallbacks<State, StateMutator, Metadata extends BaseMetadata> = { /** * @description Called when the store is initialized */ onInit?: (args: StoreTools<State, StateMutator, Metadata>) => void; /** * @description Called when the state has changed */ onStateChanged?: (args: StoreTools<State, StateMutator, Metadata> & StateChanges<State>) => void; /** * @description Called when a new subscription is created */ onSubscribed?: (args: StoreTools<State, StateMutator, Metadata>, subscription: SubscriberParameters) => void; /** * @description Called to determine whether to prevent a state change */ computePreventStateChange?: (args: StoreTools<State, StateMutator, Metadata> & StateChanges<State>) => boolean; /** * @description Called when the store is unmounted, only applicable in context stores */ onUnMount?: (store: StoreTools<State, StateMutator, Metadata>) => void; }; export type MetadataGetter<Metadata extends BaseMetadata> = () => Metadata; export type ObservableFragment<State, StateMutator, Metadata extends BaseMetadata> = SubscribeToState<State> & Pick<StateApi<State, StateMutator, Metadata>, "getState" | "subscribe" | "createSelectorHook" | "createObservable" | "dispose" | "subscribers">;