UNPKG

fluidstate

Version:

Library for fine-grained reactivity state management

102 lines (99 loc) 4.37 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.createReaction = exports.createCleanup = exports.cleanupsMap = void 0; var _reactiveLayer = require("./reactive-layer"); var _reactiveOptions = require("./reactive-options"); var _reactiveTracking = require("./reactive-tracking"); let runningReaction = null; const cleanupsMap = new WeakMap(); /** * Registers a cleanup function to be executed when the currently running reaction * is stopped or before it re-runs. * * This function must be called from within the `effect` function of a `createReaction` call. * If called outside of a reaction's execution context, it will throw an error. * * Cleanup functions are useful for releasing resources, unsubscribing from event listeners, * or performing any other necessary teardown operations associated with a reaction's lifecycle. * Each time the reaction's effect is about to re-run, or when the reaction is explicitly stopped, * all registered cleanup functions for that reaction are executed. After execution, * they are typically removed, so they don't run again unless re-registered in a subsequent * execution of the reaction's effect. * * @param cleanup - The function to be executed. This function takes no arguments and * its return value is ignored. * @throws Error if called outside the execution context of a reaction. */ exports.cleanupsMap = cleanupsMap; const createCleanup = cleanup => { if (!runningReaction) { throw new Error(`Cannot run createCleanup outside of reaction`); } let cleanups = cleanupsMap.get(runningReaction); if (!cleanups) { cleanups = []; cleanupsMap.set(runningReaction, cleanups); } cleanups.push(cleanup); }; /** * Creates a reaction that tracks dependencies and executes a side-effect function. * * A reaction observes reactive atoms and computed atoms accessed within its `effect` function. * It runs the `effect` immediately upon creation (or as per the scheduler, if provided in options) * and then re-runs the `effect` whenever any of its detected dependencies change. * Reactions are the primary mechanism for triggering side-effects (such as UI updates, * logging, or network requests) in response to changes in reactive state. * * This function utilizes the currently configured reactive layer (set via `provideReactiveLayer`) * to create the underlying reaction. It wraps the layer's reaction to provide a consistent * API within `fluidstate`. * * @param effect - The side-effect function to execute. This function will be tracked for * dependencies on reactive atoms and computed atoms. It will be re-executed when these * dependencies change. * @param options - Optional. Configuration for the reaction. This can include: * - `scheduler`: A function to control when the reaction's `effect` is run (e.g., to batch updates * or defer execution). If not provided, the effect runs immediately. * If options or specific properties within options are not provided, default behaviors are used. * @returns A `Reaction` object with a `stop` method. Calling `stop()` will permanently * dispose of the reaction, preventing it from tracking further changes or re-running its `effect`. */ exports.createCleanup = createCleanup; const createReaction = (effect, options) => { const reaction = { stop: () => { runCleanup(reaction); layerReaction.stop(); } }; const layerReaction = (0, _reactiveLayer.getReactiveLayer)().createReaction(() => { runCleanup(reaction); const previousRunningReaction = runningReaction; const previousDerivation = (0, _reactiveTracking.getTrackingDerivation)(); runningReaction = reaction; (0, _reactiveTracking.setTrackingDerivation)(reaction); try { effect(); } finally { runningReaction = previousRunningReaction; (0, _reactiveTracking.setTrackingDerivation)(previousDerivation); } }, !options ? _reactiveOptions.defaultReactionOptions : { ..._reactiveOptions.defaultReactionOptions, ...options }); return reaction; }; exports.createReaction = createReaction; const runCleanup = reaction => { (0, _reactiveTracking.untrack)(() => { cleanupsMap.get(reaction)?.forEach(cleanup => { cleanup(); }); cleanupsMap.delete(reaction); }); }; //# sourceMappingURL=reactive-reaction.js.map