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.
199 lines (195 loc) • 6.28 kB
text/typescript
/**
* 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;
}
/**
* 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 options 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, options?: RvInitOptions<T>): Rv<T>;
declare namespace rv {
var fn: <T>(init: () => T, options?: RvInitOptions<T>) => Rv<T>;
}
/**
* 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;
export { type CleanupFn, type EqualFn, type Listener, type Rv, type RvInit, type RvInitOptions, type RvOptions, rv, useRv };