Skip to content

Commit 3bd79e3

Browse files
authored
fix(reactivity): fix side effect computed dirty level (#11183)
close #11181, #11169
1 parent dadb363 commit 3bd79e3

File tree

3 files changed

+65
-2
lines changed

3 files changed

+65
-2
lines changed

packages/reactivity/__tests__/computed.spec.ts

+57
Original file line numberDiff line numberDiff line change
@@ -708,6 +708,63 @@ describe('reactivity/computed', () => {
708708
expect(COMPUTED_SIDE_EFFECT_WARN).toHaveBeenWarned()
709709
})
710710

711+
it('should chained computeds keep reactivity when computed effect happens', async () => {
712+
const v = ref('Hello')
713+
const c = computed(() => {
714+
v.value += ' World'
715+
return v.value
716+
})
717+
const d = computed(() => c.value)
718+
const e = computed(() => d.value)
719+
const Comp = {
720+
setup: () => {
721+
return () => d.value + ' | ' + e.value
722+
},
723+
}
724+
const root = nodeOps.createElement('div')
725+
726+
render(h(Comp), root)
727+
await nextTick()
728+
expect(serializeInner(root)).toBe('Hello World | Hello World')
729+
730+
v.value += ' World'
731+
await nextTick()
732+
expect(serializeInner(root)).toBe(
733+
'Hello World World World | Hello World World World',
734+
)
735+
expect(COMPUTED_SIDE_EFFECT_WARN).toHaveBeenWarned()
736+
})
737+
738+
it('should keep dirty level when side effect computed value changed', () => {
739+
const v = ref(0)
740+
const c = computed(() => {
741+
v.value += 1
742+
return v.value
743+
})
744+
const d = computed(() => {
745+
return { d: c.value }
746+
})
747+
748+
const Comp = {
749+
setup: () => {
750+
return () => {
751+
return [d.value.d, d.value.d]
752+
}
753+
},
754+
}
755+
756+
const root = nodeOps.createElement('div')
757+
render(h(Comp), root)
758+
759+
expect(d.value.d).toBe(1)
760+
expect(serializeInner(root)).toBe('11')
761+
expect(c.effect._dirtyLevel).toBe(
762+
DirtyLevels.MaybeDirty_ComputedSideEffect_Origin,
763+
)
764+
expect(d.effect._dirtyLevel).toBe(DirtyLevels.MaybeDirty_ComputedSideEffect)
765+
expect(COMPUTED_SIDE_EFFECT_WARN).toHaveBeenWarned()
766+
})
767+
711768
it('debug: onTrigger (ref)', () => {
712769
let events: DebuggerEvent[] = []
713770
const onTrigger = vi.fn((e: DebuggerEvent) => {

packages/reactivity/src/computed.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -71,11 +71,15 @@ export class ComputedRefImpl<T> {
7171
get value() {
7272
// the computed ref may get wrapped by other proxies e.g. readonly() #3376
7373
const self = toRaw(this)
74+
const lastDirtyLevel = self.effect._dirtyLevel
7475
if (
7576
(!self._cacheable || self.effect.dirty) &&
7677
hasChanged(self._value, (self._value = self.effect.run()!))
7778
) {
78-
triggerRefValue(self, DirtyLevels.Dirty)
79+
// keep dirty level when side effect computed's value changed
80+
if (lastDirtyLevel !== DirtyLevels.MaybeDirty_ComputedSideEffect) {
81+
triggerRefValue(self, DirtyLevels.Dirty)
82+
}
7983
}
8084
trackRefValue(self)
8185
if (

packages/reactivity/src/effect.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -93,8 +93,10 @@ export class ReactiveEffect<T = any> {
9393
if (
9494
dep.computed.effect._dirtyLevel ===
9595
DirtyLevels.MaybeDirty_ComputedSideEffect_Origin
96-
)
96+
) {
97+
resetTracking()
9798
return true
99+
}
98100
triggerComputed(dep.computed)
99101
if (this._dirtyLevel >= DirtyLevels.Dirty) {
100102
break

0 commit comments

Comments
 (0)