UNPKG

react-rv

Version:

react-rv is a lightweight and efficient state management library for React that allows you to create reactive variables and subscribe to them with minimal overhead.

244 lines (239 loc) 7.52 kB
/** * A function that listens to reactive variable updates. * * @template T The type of the value being listened to. * * @param val The updated value of the reactive variable. * @param old The old value of the reactive variable. */ type Listener<T> = (val: T, old: T) => void; /** * A function that cleans up event listener. */ type CleanupFn = () => void; /** * A function to compare old and new values for equality. * * @template T The type of values being compared. * * @param oldValue The previous value. * @param newValue The new value to compare against. * * @returns `true` if values are considered equal, `false` otherwise. */ type EqualFn<T> = (oldValue: T, newValue: T) => boolean; /** * Options for configuring a reactive variable. * * @template T The type of the reactive variable's value. */ type RvOptions<T> = { /** * Custom equality function to determine if the value should update. * If set to `false`, the default equality function will be used. */ eq?: false | EqualFn<T>; }; /** * A reactive variable (RV) function that allows getting, setting, and subscribing to changes. * * @template T The type of the stored value. */ interface Rv<T> { /** * Retrieves the current value of the reactive variable. * * @returns The current value of type `T`. */ (): T; /** * Updates the value of the reactive variable. * * @param newValue The new value to set. * @param options Optional configuration for the update. * * @returns The updated value. */ (newValue: T, options?: RvOptions<T>): T; /** * Subscribes a listener to value changes. * * @param listener A callback function that is triggered when the value changes. * * @returns A cleanup function to remove the listener. */ on: (listener: Listener<T>) => CleanupFn; /** * Unsubscribes a listener from value changes. * * @param listener A callback function that is needed to be unsubscribed. */ off: (listener: Listener<T>) => void; /** * Returns the number of listeners for this reactive variable. * * @returns listener count. */ size: () => number; } /** * Configuration options for initializing a reactive variable. * * @template T The type of the reactive variable's value. */ type RvInitOptions<T> = { /** * Custom equality function to determine if the value should update. */ eq?: EqualFn<T>; /** * A callback function triggered whenever the reactive variable is updated. * * @param val The new value of the reactive variable. */ on?: Listener<T>; }; /** * A factory function for creating reactive variables. */ interface RvInit { /** * Creates a reactive variable (RV), allowing value retrieval, updates, and subscriptions. * * @template T The type of the stored value. * * @param val The initial value of the reactive variable. * @param options Optional configuration for the reactive variable. * * @returns A reactive variable function that allows getting, setting, and listening for updates. */ <T>(val: T, options?: RvInitOptions<T>): Rv<T>; /** * Creates a reactive variable from an initializer function. * The function is immediately executed to determine the initial value. * * @template T The type of the stored value. * * @param init A function that returns the initial value. * @param options Optional configuration for equality comparison and event listeners. * * @returns A reactive variable function. */ fn: <T>(init: () => T, options?: RvInitOptions<T>) => Rv<T>; } /** * Creates a reactive variable (RV), allowing value retrieval, updates, and subscriptions. * * @template T The type of the stored value. * * @param val The initial value of the reactive variable. * @param opts Optional configuration for the reactive variable. * * @returns A reactive variable function that allows getting, setting, and listening for updates. * * @example * ```ts * // initialize a state variable with initial value set to 0 * const positiveVar = rv(0, { * // all options are optional * * // define custom `eq` function that will be run on every value set to determine * // whether or not value is going to be updated * eq: (oldValue, newValue) => newValue > oldValue && newValue >= 0, * * // define callback that's going to be run on every change * on: (newValue, oldValue) => {} * }) * * // alternatively, there's a handy function initializer * // all options are identical * const positiveVar = rv.fn(() => 0) * * // call variable function with no arguments to get its current value * const currentValue = positiveVar() * * // call variable function passing an argument in order to set it * // Won't trigger an update because the values are "equal" under this custom rule. * positiveVar(-3, { * // override the initial `eq` function for this update call. * eq: (oldValue, newValue) => newValue > oldValue * // additionally, you can disable initial `eq` function by passing `false` here * // it will use a default `eq` function which is just a strict check: `===` * eq: false // in this case, update WILL happen * }) * * // you can also subscribe to value without using any hooks * const unsubscribe = positiveVar.on((newValue, oldValue) => console.log(newValue, oldValue)) * * positiveVar(4) // logs: 4 * * unsubscribe() * * positiveVar(5) // there will be no logs * ``` */ declare function rv<T>(val: T, opts?: RvInitOptions<T>): Rv<T>; declare namespace rv { var fn: <T>(init: () => T, options?: RvInitOptions<T>) => Rv<T>; } declare namespace rv { /** * Infers the type of the reactive variable. * * @example * ```ts * const darkMode = rv(false) * * type DarkMode = rv.infer<typeof darkMode> // infers as boolean * ``` */ type infer<T extends Rv<any>> = T extends Rv<infer X> ? X : never; } /** * Subscribes to a reactive variable and provides its current value, * updating the state when the variable is updated. * * @template T The type of the reactive variable's value. * @param rv The reactive variable to subscribe to. * * @returns The current value of the reactive variable. * * @example * ```tsx * import React from 'react' * import { rv, useRv } from 'react-rv' * * const counter = rv(0) * * const Counter = () => { * const value = useRv(counter) * return ( * <div> * <p>Count: {value}</p> * <button onClick={() => counter(value + 1)}>Increment</button> * </div> * ) * } * ``` */ declare const useRv: <T>(rv: Rv<T>) => T; /** * React hook to subscribe to updates of a reactive variable. * * Note: callback is always using current scope. * * @example * ```ts * const counter = rv(0) * * useRvEffect(counter, (newVal, oldVal) => { * console.table({ newVal, oldVal }) * }) * ``` * * @param rv - The reactive variable to subscribe to. * @param f - A callback function triggered whenever the reactive variable is updated. * The first and second arguments are the new and the old value of this `rv`. */ declare function useRvEffect<T>(rv: Rv<T>, f: Listener<T>): void; export { type CleanupFn, type EqualFn, type Listener, type Rv, type RvInit, type RvInitOptions, type RvOptions, rv, useRv, useRvEffect };