Skip to content

Commit a1167c5

Browse files
committed
fix(runtime-core): disallow recurse in vnode/directive beforeUpdate hooks
1 parent 4b0ca87 commit a1167c5

File tree

2 files changed

+24
-10
lines changed

2 files changed

+24
-10
lines changed

packages/runtime-core/src/component.ts

+7-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ import {
77
EffectScope,
88
markRaw,
99
track,
10-
TrackOpTypes
10+
TrackOpTypes,
11+
ReactiveEffect
1112
} from '@vue/reactivity'
1213
import {
1314
ComponentPublicInstance,
@@ -224,6 +225,10 @@ export interface ComponentInternalInstance {
224225
* Root vnode of this component's own vdom tree
225226
*/
226227
subTree: VNode
228+
/**
229+
* Render effect instance
230+
*/
231+
effect: ReactiveEffect
227232
/**
228233
* Bound effect runner to be passed to schedulers
229234
*/
@@ -460,6 +465,7 @@ export function createComponentInstance(
460465
root: null!, // to be immediately set
461466
next: null,
462467
subTree: null!, // will be set synchronously right after creation
468+
effect: null!,
463469
update: null!, // will be set synchronously right after creation
464470
scope: new EffectScope(true /* detached */),
465471
render: null,

packages/runtime-core/src/renderer.ts

+17-9
Original file line numberDiff line numberDiff line change
@@ -826,12 +826,15 @@ function baseCreateRenderer(
826826
const newProps = n2.props || EMPTY_OBJ
827827
let vnodeHook: VNodeHook | undefined | null
828828

829+
// disable recurse in beforeUpdate hooks
830+
parentComponent && toggleRecurse(parentComponent, false)
829831
if ((vnodeHook = newProps.onVnodeBeforeUpdate)) {
830832
invokeVNodeHook(vnodeHook, parentComponent, n2, n1)
831833
}
832834
if (dirs) {
833835
invokeDirectiveHook(n2, n1, parentComponent, 'beforeUpdate')
834836
}
837+
parentComponent && toggleRecurse(parentComponent, true)
835838

836839
if (__DEV__ && isHmrUpdating) {
837840
// HMR updated, force full diff
@@ -1318,7 +1321,7 @@ function baseCreateRenderer(
13181321
const { bm, m, parent } = instance
13191322
const isAsyncWrapperVNode = isAsyncWrapper(initialVNode)
13201323

1321-
effect.allowRecurse = false
1324+
toggleRecurse(instance, false)
13221325
// beforeMount hook
13231326
if (bm) {
13241327
invokeArrayFns(bm)
@@ -1336,7 +1339,7 @@ function baseCreateRenderer(
13361339
) {
13371340
instance.emit('hook:beforeMount')
13381341
}
1339-
effect.allowRecurse = true
1342+
toggleRecurse(instance, true)
13401343

13411344
if (el && hydrateNode) {
13421345
// vnode has adopted host node - perform hydration instead of mount.
@@ -1459,8 +1462,7 @@ function baseCreateRenderer(
14591462
}
14601463

14611464
// Disallow component effect recursion during pre-lifecycle hooks.
1462-
effect.allowRecurse = false
1463-
1465+
toggleRecurse(instance, false)
14641466
if (next) {
14651467
next.el = vnode.el
14661468
updateComponentPreRender(instance, next, optimized)
@@ -1482,8 +1484,7 @@ function baseCreateRenderer(
14821484
) {
14831485
instance.emit('hook:beforeUpdate')
14841486
}
1485-
1486-
effect.allowRecurse = true
1487+
toggleRecurse(instance, true)
14871488

14881489
// render
14891490
if (__DEV__) {
@@ -1552,17 +1553,17 @@ function baseCreateRenderer(
15521553
}
15531554

15541555
// create reactive effect for rendering
1555-
const effect = new ReactiveEffect(
1556+
const effect = (instance.effect = new ReactiveEffect(
15561557
componentUpdateFn,
15571558
() => queueJob(instance.update),
15581559
instance.scope // track it in component's effect scope
1559-
)
1560+
))
15601561

15611562
const update = (instance.update = effect.run.bind(effect) as SchedulerJob)
15621563
update.id = instance.uid
15631564
// allowRecurse
15641565
// #1801, #2043 component render effects should allow recursive updates
1565-
effect.allowRecurse = update.allowRecurse = true
1566+
toggleRecurse(instance, true)
15661567

15671568
if (__DEV__) {
15681569
effect.onTrack = instance.rtc
@@ -2455,6 +2456,13 @@ export function invokeVNodeHook(
24552456
])
24562457
}
24572458

2459+
function toggleRecurse(
2460+
{ effect, update }: ComponentInternalInstance,
2461+
allowed: boolean
2462+
) {
2463+
effect.allowRecurse = update.allowRecurse = allowed
2464+
}
2465+
24582466
/**
24592467
* #1156
24602468
* When a component is HMR-enabled, we need to make sure that all static nodes

0 commit comments

Comments
 (0)