fix(runtime-core): disable block tracking when calling compiled slot function in tempalte expressions

fix #1745, fix #1918
This commit is contained in:
Evan You
2020-08-21 12:47:45 -04:00
parent c0411b3745
commit f02e2f99d9
3 changed files with 22 additions and 14 deletions

View File

@@ -10,7 +10,7 @@ import {
import { PatchFlags, SlotFlags } from '@vue/shared'
import { warn } from '../warning'
export let shouldTrackInSlotRendering = 0
export let isRenderingCompiledSlot = 0
/**
* Compiler runtime helper for rendering `<slot/>`
@@ -39,7 +39,7 @@ export function renderSlot(
// invocation interfering with template-based block tracking, but in
// `renderSlot` we can be sure that it's template-based so we can force
// enable it.
shouldTrackInSlotRendering++
isRenderingCompiledSlot++
const rendered = (openBlock(),
createBlock(
Fragment,
@@ -49,6 +49,6 @@ export function renderSlot(
? PatchFlags.STABLE_FRAGMENT
: PatchFlags.BAIL
))
shouldTrackInSlotRendering--
isRenderingCompiledSlot--
return rendered
}

View File

@@ -4,7 +4,8 @@ import {
currentRenderingInstance
} from '../componentRenderUtils'
import { ComponentInternalInstance } from '../component'
import { setBlockTracking } from '../vnode'
import { isRenderingCompiledSlot } from './renderSlot'
import { closeBlock, openBlock } from '../vnode'
/**
* Wrap a slot function to memoize current rendering instance
@@ -16,15 +17,19 @@ export function withCtx(
) {
if (!ctx) return fn
return function renderFnWithContext() {
// By default, compiled slots disables block tracking since the user may
// call it inside a template expression (#1745). It should only track when
// it's called by a template `<slot>`.
setBlockTracking(-1)
// If a user calls a compiled slot inside a template expression (#1745), it
// can mess up block tracking, so by default we need to push a null block to
// avoid that. This isn't necessary if rendering a compiled `<slot>`.
if (!isRenderingCompiledSlot) {
openBlock(true /* null block that disables tracking */)
}
const owner = currentRenderingInstance
setCurrentRenderingInstance(ctx)
const res = fn.apply(null, arguments as any)
setCurrentRenderingInstance(owner)
setBlockTracking(1)
if (!isRenderingCompiledSlot) {
closeBlock()
}
return res
}
}