fix: resolveDynamicComponent should use context instance

This commit is contained in:
Evan You 2019-11-25 10:04:40 -05:00
parent 01eb3c12e9
commit 08a3d95e52
4 changed files with 35 additions and 9 deletions

View File

@ -788,7 +788,8 @@ describe('compiler: element transform', () => {
{ {
type: NodeTypes.SIMPLE_EXPRESSION, type: NodeTypes.SIMPLE_EXPRESSION,
content: 'foo' content: 'foo'
} },
'$'
] ]
} }
]) ])

View File

@ -86,7 +86,8 @@ export const transformElement: NodeTransform = (node, context) => {
else if (isProp.exp) { else if (isProp.exp) {
dynamicComponent = createCallExpression( dynamicComponent = createCallExpression(
context.helper(RESOLVE_DYNAMIC_COMPONENT), context.helper(RESOLVE_DYNAMIC_COMPONENT),
[isProp.exp] // _ctx.$ exposes the owner instance of current render function
[isProp.exp, context.prefixIdentifiers ? `_ctx.$` : `$`]
) )
} }
} }

View File

@ -106,6 +106,9 @@ export const PublicInstanceProxyHandlers: ProxyHandler<any> = {
} }
// return the value from propsProxy for ref unwrapping and readonly // return the value from propsProxy for ref unwrapping and readonly
return propsProxy![key] return propsProxy![key]
} else if (key === '$') {
// reserved backdoor to access the internal instance
return target
} else if (key === '$cache') { } else if (key === '$cache') {
return target.renderCache || (target.renderCache = []) return target.renderCache || (target.renderCache = [])
} else if (key === '$el') { } else if (key === '$el') {

View File

@ -1,5 +1,9 @@
import { currentRenderingInstance } from '../componentRenderUtils' import { currentRenderingInstance } from '../componentRenderUtils'
import { currentInstance, Component } from '../component' import {
currentInstance,
Component,
ComponentInternalInstance
} from '../component'
import { Directive } from '../directives' import { Directive } from '../directives'
import { import {
camelize, camelize,
@ -15,11 +19,16 @@ export function resolveComponent(name: string): Component | undefined {
} }
export function resolveDynamicComponent( export function resolveDynamicComponent(
component: unknown component: unknown,
// Dynamic component resolution has to be called inline due to potential
// access to scope variables. When called inside slots it will be inside
// a different component's render cycle, so the owner instance must be passed
// in explicitly.
instance: ComponentInternalInstance
): Component | undefined { ): Component | undefined {
if (!component) return if (!component) return
if (isString(component)) { if (isString(component)) {
return resolveAsset('components', component) return resolveAsset('components', component, instance)
} else if (isFunction(component) || isObject(component)) { } else if (isFunction(component) || isObject(component)) {
return component return component
} }
@ -30,12 +39,24 @@ export function resolveDirective(name: string): Directive | undefined {
} }
// overload 1: components // overload 1: components
function resolveAsset(type: 'components', name: string): Component | undefined function resolveAsset(
type: 'components',
name: string,
instance?: ComponentInternalInstance
): Component | undefined
// overload 2: directives // overload 2: directives
function resolveAsset(type: 'directives', name: string): Directive | undefined function resolveAsset(
type: 'directives',
name: string,
instance?: ComponentInternalInstance
): Directive | undefined
function resolveAsset(type: 'components' | 'directives', name: string) { function resolveAsset(
const instance = currentRenderingInstance || currentInstance type: 'components' | 'directives',
name: string,
instance: ComponentInternalInstance | null = currentRenderingInstance ||
currentInstance
) {
if (instance) { if (instance) {
let camelized let camelized
const registry = instance[type] const registry = instance[type]