Skip to content

Commit 28841fe

Browse files
authored
fix(reactivity): fix call sequence of ontrigger in effect (#10501)
1 parent 85f3592 commit 28841fe

File tree

2 files changed

+109
-15
lines changed

2 files changed

+109
-15
lines changed

Diff for: packages/reactivity/__tests__/effect.spec.ts

+71
Original file line numberDiff line numberDiff line change
@@ -769,6 +769,32 @@ describe('reactivity/effect', () => {
769769
])
770770
})
771771

772+
it('debug: the call sequence of onTrack', () => {
773+
const seq: number[] = []
774+
const s = ref(0)
775+
776+
const track1 = () => seq.push(1)
777+
const track2 = () => seq.push(2)
778+
779+
effect(
780+
() => {
781+
s.value
782+
},
783+
{
784+
onTrack: track1,
785+
},
786+
)
787+
effect(
788+
() => {
789+
s.value
790+
},
791+
{
792+
onTrack: track2,
793+
},
794+
)
795+
expect(seq.toString()).toBe('1,2')
796+
})
797+
772798
it('events: onTrigger', () => {
773799
let events: DebuggerEvent[] = []
774800
let dummy
@@ -807,6 +833,51 @@ describe('reactivity/effect', () => {
807833
})
808834
})
809835

836+
it('debug: the call sequence of onTrigger', () => {
837+
const seq: number[] = []
838+
const s = ref(0)
839+
840+
const trigger1 = () => seq.push(1)
841+
const trigger2 = () => seq.push(2)
842+
const trigger3 = () => seq.push(3)
843+
const trigger4 = () => seq.push(4)
844+
845+
effect(
846+
() => {
847+
s.value
848+
},
849+
{
850+
onTrigger: trigger1,
851+
},
852+
)
853+
effect(
854+
() => {
855+
s.value
856+
effect(
857+
() => {
858+
s.value
859+
effect(
860+
() => {
861+
s.value
862+
},
863+
{
864+
onTrigger: trigger4,
865+
},
866+
)
867+
},
868+
{
869+
onTrigger: trigger3,
870+
},
871+
)
872+
},
873+
{
874+
onTrigger: trigger2,
875+
},
876+
)
877+
s.value++
878+
expect(seq.toString()).toBe('1,2,3,4')
879+
})
880+
810881
it('stop', () => {
811882
let dummy
812883
const obj = reactive({ prop: 1 })

Diff for: packages/reactivity/src/dep.ts

+38-15
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,23 @@ export class Dep {
2727
* Link between this dep and the current active effect
2828
*/
2929
activeLink?: Link = undefined
30+
3031
/**
3132
* Doubly linked list representing the subscribing effects (tail)
3233
*/
3334
subs?: Link = undefined
3435

35-
constructor(public computed?: ComputedRefImpl) {}
36+
/**
37+
* Doubly linked list representing the subscribing effects (head)
38+
* DEV only, for invoking onTrigger hooks in correct order
39+
*/
40+
subsHead?: Link
41+
42+
constructor(public computed?: ComputedRefImpl) {
43+
if (__DEV__) {
44+
this.subsHead = undefined
45+
}
46+
}
3647

3748
track(debugInfo?: DebuggerEventExtraInfo): Link | undefined {
3849
if (!activeSub || !shouldTrack) {
@@ -113,21 +124,28 @@ export class Dep {
113124
notify(debugInfo?: DebuggerEventExtraInfo) {
114125
startBatch()
115126
try {
116-
for (let link = this.subs; link; link = link.prevSub) {
117-
if (
118-
__DEV__ &&
119-
link.sub.onTrigger &&
120-
!(link.sub.flags & EffectFlags.NOTIFIED)
121-
) {
122-
link.sub.onTrigger(
123-
extend(
124-
{
125-
effect: link.sub,
126-
},
127-
debugInfo,
128-
),
129-
)
127+
if (__DEV__) {
128+
// subs are notified and batched in reverse-order and then invoked in
129+
// original order at the end of the batch, but onTrigger hooks should
130+
// be invoked in original order here.
131+
for (let head = this.subsHead; head; head = head.nextSub) {
132+
if (
133+
__DEV__ &&
134+
head.sub.onTrigger &&
135+
!(head.sub.flags & EffectFlags.NOTIFIED)
136+
) {
137+
head.sub.onTrigger(
138+
extend(
139+
{
140+
effect: head.sub,
141+
},
142+
debugInfo,
143+
),
144+
)
145+
}
130146
}
147+
}
148+
for (let link = this.subs; link; link = link.prevSub) {
131149
link.sub.notify()
132150
}
133151
} finally {
@@ -152,6 +170,11 @@ function addSub(link: Link) {
152170
link.prevSub = currentTail
153171
if (currentTail) currentTail.nextSub = link
154172
}
173+
174+
if (__DEV__ && link.dep.subsHead === undefined) {
175+
link.dep.subsHead = link
176+
}
177+
155178
link.dep.subs = link
156179
}
157180

0 commit comments

Comments
 (0)