2024-02-07 16:21:22 +03:00

92 lines
2.5 KiB
TypeScript

import type { IReactionDisposer, IReactionOptions, IReactionPublic } from 'mobx';
import { reaction } from 'mobx';
import { debounce, omit } from 'radash';
export function disposableReaction<T, FireImmediately extends boolean = false>(
disposeExpression: () => boolean,
expression: (r: IReactionPublic) => T,
effect: (
arg: T,
prev: FireImmediately extends true ? T | undefined : T,
r: IReactionPublic
) => void,
reactionOpts?: IReactionOptions<T, FireImmediately>
) {
let disposer: IReactionDisposer | undefined;
if (!disposeExpression()) {
disposer = reaction(expression, effect, reactionOpts);
}
function cleanDisposer() {
disposer = undefined;
}
reaction(disposeExpression, (mustBeDisposed) => {
if (mustBeDisposed) {
if (disposer !== undefined) disposer();
cleanDisposer();
} else {
setTimeout(() => {
disposer = reaction(
expression,
effect,
reactionOpts ? omit(reactionOpts, ['fireImmediately']) : undefined
);
}, 100);
}
});
}
export function debouncedReaction<T, FireImmediately extends boolean = false>(
expression: (r: IReactionPublic) => T,
effect: (
arg: T,
prev: FireImmediately extends true ? T | undefined : T,
r: IReactionPublic
) => void,
{ wait, ...reactionOpts }: IReactionOptions<T, FireImmediately> & { wait: number }
): IReactionDisposer {
const debouncedEffect = debounce({ delay: wait }, effect);
return reaction(expression, debouncedEffect, reactionOpts);
}
export function disposableDebouncedReaction<T, FireImmediately extends boolean = false>(
disposeExpression: () => boolean,
expression: (r: IReactionPublic) => T,
effect: (
arg: T,
prev: FireImmediately extends true ? T | undefined : T,
r: IReactionPublic
) => void,
{ wait, ...reactionOpts }: IReactionOptions<T, FireImmediately> & { wait: number }
) {
const debouncedEffect = debounce({ delay: wait }, effect);
let disposer: IReactionDisposer | undefined;
if (!disposeExpression()) {
disposer = reaction(expression, debouncedEffect, reactionOpts);
}
function cleanDisposer() {
disposer = undefined;
}
reaction(disposeExpression, (mustBeDisposed) => {
if (mustBeDisposed) {
if (disposer !== undefined) disposer();
cleanDisposer();
} else {
setTimeout(() => {
disposer = reaction(
expression,
debouncedEffect,
reactionOpts ? omit(reactionOpts, ['fireImmediately']) : undefined
);
}, 100);
}
});
}