fluidstate
Version:
Library for fine-grained reactivity state management
102 lines (99 loc) • 4.37 kB
JavaScript
;
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