mirror of https://github.com/vuejs/core.git
parent
e58d3f69fc
commit
c2b274a887
|
@ -2,6 +2,7 @@ import { h, nextTick, nodeOps, render, serializeInner } from '@vue/runtime-test'
|
||||||
import {
|
import {
|
||||||
type DebuggerEvent,
|
type DebuggerEvent,
|
||||||
ITERATE_KEY,
|
ITERATE_KEY,
|
||||||
|
ReactiveEffect,
|
||||||
TrackOpTypes,
|
TrackOpTypes,
|
||||||
TriggerOpTypes,
|
TriggerOpTypes,
|
||||||
type WritableComputedRef,
|
type WritableComputedRef,
|
||||||
|
@ -454,14 +455,10 @@ describe('reactivity/computed', () => {
|
||||||
expect(fnSpy).toBeCalledTimes(2)
|
expect(fnSpy).toBeCalledTimes(2)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('...', () => {
|
it('should chained recurse effects clear dirty after trigger', () => {
|
||||||
const fnSpy = vi.fn()
|
|
||||||
const v = ref(1)
|
const v = ref(1)
|
||||||
const c1 = computed(() => v.value)
|
const c1 = computed(() => v.value)
|
||||||
const c2 = computed(() => {
|
const c2 = computed(() => c1.value)
|
||||||
fnSpy()
|
|
||||||
return c1.value
|
|
||||||
})
|
|
||||||
|
|
||||||
c1.effect.allowRecurse = true
|
c1.effect.allowRecurse = true
|
||||||
c2.effect.allowRecurse = true
|
c2.effect.allowRecurse = true
|
||||||
|
@ -471,6 +468,60 @@ describe('reactivity/computed', () => {
|
||||||
expect(c2.effect._dirtyLevel).toBe(DirtyLevels.NotDirty)
|
expect(c2.effect._dirtyLevel).toBe(DirtyLevels.NotDirty)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should chained computeds dirtyLevel update with first computed effect', () => {
|
||||||
|
const v = ref(0)
|
||||||
|
const c1 = computed(() => {
|
||||||
|
if (v.value === 0) {
|
||||||
|
v.value = 1
|
||||||
|
}
|
||||||
|
return v.value
|
||||||
|
})
|
||||||
|
const c2 = computed(() => c1.value)
|
||||||
|
const c3 = computed(() => c2.value)
|
||||||
|
|
||||||
|
c3.value
|
||||||
|
|
||||||
|
expect(c1.effect._dirtyLevel).toBe(DirtyLevels.Dirty)
|
||||||
|
expect(c2.effect._dirtyLevel).toBe(DirtyLevels.MaybeDirty)
|
||||||
|
expect(c3.effect._dirtyLevel).toBe(DirtyLevels.MaybeDirty)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should work when chained(ref+computed)', () => {
|
||||||
|
const v = ref(0)
|
||||||
|
const c1 = computed(() => {
|
||||||
|
if (v.value === 0) {
|
||||||
|
v.value = 1
|
||||||
|
}
|
||||||
|
return 'foo'
|
||||||
|
})
|
||||||
|
const c2 = computed(() => v.value + c1.value)
|
||||||
|
expect(c2.value).toBe('0foo')
|
||||||
|
expect(c2.effect._dirtyLevel).toBe(DirtyLevels.Dirty)
|
||||||
|
expect(c2.value).toBe('1foo')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should trigger effect even computed already dirty', () => {
|
||||||
|
const fnSpy = vi.fn()
|
||||||
|
const v = ref(0)
|
||||||
|
const c1 = computed(() => {
|
||||||
|
if (v.value === 0) {
|
||||||
|
v.value = 1
|
||||||
|
}
|
||||||
|
return 'foo'
|
||||||
|
})
|
||||||
|
const c2 = computed(() => v.value + c1.value)
|
||||||
|
|
||||||
|
effect(() => {
|
||||||
|
fnSpy()
|
||||||
|
c2.value
|
||||||
|
})
|
||||||
|
expect(fnSpy).toBeCalledTimes(1)
|
||||||
|
expect(c1.effect._dirtyLevel).toBe(DirtyLevels.Dirty)
|
||||||
|
expect(c2.effect._dirtyLevel).toBe(DirtyLevels.Dirty)
|
||||||
|
v.value = 2
|
||||||
|
expect(fnSpy).toBeCalledTimes(2)
|
||||||
|
})
|
||||||
|
|
||||||
it('should be not dirty after deps mutate (mutate deps in computed)', async () => {
|
it('should be not dirty after deps mutate (mutate deps in computed)', async () => {
|
||||||
const state = reactive<any>({})
|
const state = reactive<any>({})
|
||||||
const consumer = computed(() => {
|
const consumer = computed(() => {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { type DebuggerOptions, ReactiveEffect } from './effect'
|
import { type DebuggerOptions, ReactiveEffect, scheduleEffects } from './effect'
|
||||||
import { type Ref, trackRefValue, triggerRefValue } from './ref'
|
import { type Ref, trackRefValue, triggerRefValue } from './ref'
|
||||||
import { NOOP, hasChanged, isFunction } from '@vue/shared'
|
import { NOOP, hasChanged, isFunction } from '@vue/shared'
|
||||||
import { toRaw } from './reactive'
|
import { toRaw } from './reactive'
|
||||||
|
@ -44,6 +44,7 @@ export class ComputedRefImpl<T> {
|
||||||
this.effect = new ReactiveEffect(
|
this.effect = new ReactiveEffect(
|
||||||
() => getter(this._value),
|
() => getter(this._value),
|
||||||
() => triggerRefValue(this, DirtyLevels.MaybeDirty),
|
() => triggerRefValue(this, DirtyLevels.MaybeDirty),
|
||||||
|
() => this.dep && scheduleEffects(this.dep),
|
||||||
)
|
)
|
||||||
this.effect.computed = this
|
this.effect.computed = this
|
||||||
this.effect.active = this._cacheable = !isSSR
|
this.effect.active = this._cacheable = !isSSR
|
||||||
|
@ -59,6 +60,9 @@ export class ComputedRefImpl<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
trackRefValue(self)
|
trackRefValue(self)
|
||||||
|
if (self.effect._dirtyLevel >= DirtyLevels.MaybeDirty) {
|
||||||
|
triggerRefValue(self, DirtyLevels.MaybeDirty)
|
||||||
|
}
|
||||||
return self._value
|
return self._value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -291,13 +291,9 @@ export function triggerEffects(
|
||||||
) {
|
) {
|
||||||
pauseScheduling()
|
pauseScheduling()
|
||||||
for (const effect of dep.keys()) {
|
for (const effect of dep.keys()) {
|
||||||
if (dep.get(effect) !== effect._trackId) {
|
|
||||||
// when recurse effect is running, dep map could have outdated items
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if (
|
if (
|
||||||
effect._dirtyLevel < dirtyLevel &&
|
effect._dirtyLevel < dirtyLevel &&
|
||||||
!(effect._runnings && !effect.allowRecurse)
|
dep.get(effect) === effect._trackId
|
||||||
) {
|
) {
|
||||||
const lastDirtyLevel = effect._dirtyLevel
|
const lastDirtyLevel = effect._dirtyLevel
|
||||||
effect._dirtyLevel = dirtyLevel
|
effect._dirtyLevel = dirtyLevel
|
||||||
|
@ -309,14 +305,21 @@ export function triggerEffects(
|
||||||
effect.trigger()
|
effect.trigger()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
scheduleEffects(dep)
|
||||||
|
resetScheduling()
|
||||||
|
}
|
||||||
|
|
||||||
|
export function scheduleEffects(dep: Dep) {
|
||||||
|
for (const effect of dep.keys()) {
|
||||||
if (
|
if (
|
||||||
effect.scheduler &&
|
effect.scheduler &&
|
||||||
effect._shouldSchedule &&
|
effect._shouldSchedule &&
|
||||||
(!effect._runnings || effect.allowRecurse)
|
(!effect._runnings || effect.allowRecurse) &&
|
||||||
|
dep.get(effect) === effect._trackId
|
||||||
) {
|
) {
|
||||||
effect._shouldSchedule = false
|
effect._shouldSchedule = false
|
||||||
queueEffectSchedulers.push(effect.scheduler)
|
queueEffectSchedulers.push(effect.scheduler)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
resetScheduling()
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue