92 lines
2.5 KiB
TypeScript
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);
|
|
}
|
|
});
|
|
}
|