fix(runtime-core): disable block tracking when calling compiled slot function in tempalte expressions
fix #1745, fix #1918
This commit is contained in:
parent
c0411b3745
commit
f02e2f99d9
@ -10,7 +10,7 @@ import {
|
|||||||
import { PatchFlags, SlotFlags } from '@vue/shared'
|
import { PatchFlags, SlotFlags } from '@vue/shared'
|
||||||
import { warn } from '../warning'
|
import { warn } from '../warning'
|
||||||
|
|
||||||
export let shouldTrackInSlotRendering = 0
|
export let isRenderingCompiledSlot = 0
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compiler runtime helper for rendering `<slot/>`
|
* Compiler runtime helper for rendering `<slot/>`
|
||||||
@ -39,7 +39,7 @@ export function renderSlot(
|
|||||||
// invocation interfering with template-based block tracking, but in
|
// invocation interfering with template-based block tracking, but in
|
||||||
// `renderSlot` we can be sure that it's template-based so we can force
|
// `renderSlot` we can be sure that it's template-based so we can force
|
||||||
// enable it.
|
// enable it.
|
||||||
shouldTrackInSlotRendering++
|
isRenderingCompiledSlot++
|
||||||
const rendered = (openBlock(),
|
const rendered = (openBlock(),
|
||||||
createBlock(
|
createBlock(
|
||||||
Fragment,
|
Fragment,
|
||||||
@ -49,6 +49,6 @@ export function renderSlot(
|
|||||||
? PatchFlags.STABLE_FRAGMENT
|
? PatchFlags.STABLE_FRAGMENT
|
||||||
: PatchFlags.BAIL
|
: PatchFlags.BAIL
|
||||||
))
|
))
|
||||||
shouldTrackInSlotRendering--
|
isRenderingCompiledSlot--
|
||||||
return rendered
|
return rendered
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,8 @@ import {
|
|||||||
currentRenderingInstance
|
currentRenderingInstance
|
||||||
} from '../componentRenderUtils'
|
} from '../componentRenderUtils'
|
||||||
import { ComponentInternalInstance } from '../component'
|
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
|
* Wrap a slot function to memoize current rendering instance
|
||||||
@ -16,15 +17,19 @@ export function withCtx(
|
|||||||
) {
|
) {
|
||||||
if (!ctx) return fn
|
if (!ctx) return fn
|
||||||
return function renderFnWithContext() {
|
return function renderFnWithContext() {
|
||||||
// By default, compiled slots disables block tracking since the user may
|
// If a user calls a compiled slot inside a template expression (#1745), it
|
||||||
// call it inside a template expression (#1745). It should only track when
|
// can mess up block tracking, so by default we need to push a null block to
|
||||||
// it's called by a template `<slot>`.
|
// avoid that. This isn't necessary if rendering a compiled `<slot>`.
|
||||||
setBlockTracking(-1)
|
if (!isRenderingCompiledSlot) {
|
||||||
|
openBlock(true /* null block that disables tracking */)
|
||||||
|
}
|
||||||
const owner = currentRenderingInstance
|
const owner = currentRenderingInstance
|
||||||
setCurrentRenderingInstance(ctx)
|
setCurrentRenderingInstance(ctx)
|
||||||
const res = fn.apply(null, arguments as any)
|
const res = fn.apply(null, arguments as any)
|
||||||
setCurrentRenderingInstance(owner)
|
setCurrentRenderingInstance(owner)
|
||||||
setBlockTracking(1)
|
if (!isRenderingCompiledSlot) {
|
||||||
|
closeBlock()
|
||||||
|
}
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,6 @@ import { currentRenderingInstance } from './componentRenderUtils'
|
|||||||
import { RendererNode, RendererElement } from './renderer'
|
import { RendererNode, RendererElement } from './renderer'
|
||||||
import { NULL_DYNAMIC_COMPONENT } from './helpers/resolveAssets'
|
import { NULL_DYNAMIC_COMPONENT } from './helpers/resolveAssets'
|
||||||
import { hmrDirtyComponents } from './hmr'
|
import { hmrDirtyComponents } from './hmr'
|
||||||
import { shouldTrackInSlotRendering } from './helpers/renderSlot'
|
|
||||||
|
|
||||||
export const Fragment = (Symbol(__DEV__ ? 'Fragment' : undefined) as any) as {
|
export const Fragment = (Symbol(__DEV__ ? 'Fragment' : undefined) as any) as {
|
||||||
__isFragment: true
|
__isFragment: true
|
||||||
@ -153,7 +152,7 @@ export interface VNode<
|
|||||||
// can divide a template into nested blocks, and within each block the node
|
// can divide a template into nested blocks, and within each block the node
|
||||||
// structure would be stable. This allows us to skip most children diffing
|
// structure would be stable. This allows us to skip most children diffing
|
||||||
// and only worry about the dynamic nodes (indicated by patch flags).
|
// and only worry about the dynamic nodes (indicated by patch flags).
|
||||||
const blockStack: (VNode[] | null)[] = []
|
export const blockStack: (VNode[] | null)[] = []
|
||||||
let currentBlock: VNode[] | null = null
|
let currentBlock: VNode[] | null = null
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -176,6 +175,11 @@ export function openBlock(disableTracking = false) {
|
|||||||
blockStack.push((currentBlock = disableTracking ? null : []))
|
blockStack.push((currentBlock = disableTracking ? null : []))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function closeBlock() {
|
||||||
|
blockStack.pop()
|
||||||
|
currentBlock = blockStack[blockStack.length - 1] || null
|
||||||
|
}
|
||||||
|
|
||||||
// Whether we should be tracking dynamic child nodes inside a block.
|
// Whether we should be tracking dynamic child nodes inside a block.
|
||||||
// Only tracks when this value is > 0
|
// Only tracks when this value is > 0
|
||||||
// We are not using a simple boolean because this value may need to be
|
// We are not using a simple boolean because this value may need to be
|
||||||
@ -227,8 +231,7 @@ export function createBlock(
|
|||||||
// save current block children on the block vnode
|
// save current block children on the block vnode
|
||||||
vnode.dynamicChildren = currentBlock || EMPTY_ARR
|
vnode.dynamicChildren = currentBlock || EMPTY_ARR
|
||||||
// close block
|
// close block
|
||||||
blockStack.pop()
|
closeBlock()
|
||||||
currentBlock = blockStack[blockStack.length - 1] || null
|
|
||||||
// a block is always going to be patched, so track it as a child of its
|
// a block is always going to be patched, so track it as a child of its
|
||||||
// parent block
|
// parent block
|
||||||
if (currentBlock) {
|
if (currentBlock) {
|
||||||
@ -403,7 +406,7 @@ function _createVNode(
|
|||||||
normalizeChildren(vnode, children)
|
normalizeChildren(vnode, children)
|
||||||
|
|
||||||
if (
|
if (
|
||||||
(shouldTrack > 0 || shouldTrackInSlotRendering > 0) &&
|
shouldTrack > 0 &&
|
||||||
// avoid a block node from tracking itself
|
// avoid a block node from tracking itself
|
||||||
!isBlockNode &&
|
!isBlockNode &&
|
||||||
// has current parent block
|
// has current parent block
|
||||||
|
Loading…
x
Reference in New Issue
Block a user