expect(dummy).toBe(3)
})
+ it('stop with scheduler', () => {
+ let dummy
+ const obj = reactive({ prop: 1 })
+ const queue: (() => void)[] = []
+ const runner = effect(
+ () => {
+ dummy = obj.prop
+ },
+ {
+ scheduler: e => queue.push(e)
+ }
+ )
+ obj.prop = 2
+ expect(dummy).toBe(1)
+ expect(queue.length).toBe(1)
+ stop(runner)
+
+ // a scheduled effect should not execute anymore after stopped
+ queue.forEach(e => e())
+ expect(dummy).toBe(1)
+ })
+
it('events: onStop', () => {
const onStop = jest.fn()
const runner = effect(() => {}, {
const targetMap = new WeakMap<any, KeyToDepMap>()
export interface ReactiveEffect<T = any> {
- (): T
+ (...args: any[]): T
_isEffect: true
active: boolean
raw: () => T
}
function createReactiveEffect<T = any>(
- fn: () => T,
+ fn: (...args: any[]) => T,
options: ReactiveEffectOptions
): ReactiveEffect<T> {
const effect = function reactiveEffect(...args: unknown[]): unknown {
- return run(effect, fn, args)
+ if (!effect.active) {
+ return options.scheduler ? undefined : fn(...args)
+ }
+ if (!effectStack.includes(effect)) {
+ cleanup(effect)
+ try {
+ enableTracking()
+ effectStack.push(effect)
+ activeEffect = effect
+ return fn(...args)
+ } finally {
+ effectStack.pop()
+ resetTracking()
+ activeEffect = effectStack[effectStack.length - 1]
+ }
+ }
} as ReactiveEffect
effect._isEffect = true
effect.active = true
return effect
}
-function run(effect: ReactiveEffect, fn: Function, args: unknown[]): unknown {
- if (!effect.active) {
- return fn(...args)
- }
- if (!effectStack.includes(effect)) {
- cleanup(effect)
- try {
- enableTracking()
- effectStack.push(effect)
- activeEffect = effect
- return fn(...args)
- } finally {
- effectStack.pop()
- resetTracking()
- activeEffect = effectStack[effectStack.length - 1]
- }
- }
-}
-
function cleanup(effect: ReactiveEffect) {
const { deps } = effect
if (deps.length) {