From 53f4885d9e06f1b1b0b33abc8f1c20766cbb2d1a Mon Sep 17 00:00:00 2001 From: Evan You Date: Fri, 27 Nov 2020 10:10:25 -0500 Subject: [PATCH] fix(runtime-core): skip functional components in public $parent chain traversal fix #2437 --- packages/runtime-core/src/componentPublicInstance.ts | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/packages/runtime-core/src/componentPublicInstance.ts b/packages/runtime-core/src/componentPublicInstance.ts index 2ac9b8a4..1e62f8b1 100644 --- a/packages/runtime-core/src/componentPublicInstance.ts +++ b/packages/runtime-core/src/componentPublicInstance.ts @@ -200,6 +200,16 @@ export type ComponentPublicInstance< type PublicPropertiesMap = Record any> +/** + * #2437 In Vue 3, functional components do not have a public instance proxy but + * they exist in the internal parent chain. For code that relies on traversing + * public $parent chains, skip functional ones and go to the parent instead. + */ +const getPublicInstance = ( + i: ComponentInternalInstance | null +): ComponentPublicInstance | null => + i && (i.proxy ? i.proxy : getPublicInstance(i.parent)) + const publicPropertiesMap: PublicPropertiesMap = extend(Object.create(null), { $: i => i, $el: i => i.vnode.el, @@ -208,7 +218,7 @@ const publicPropertiesMap: PublicPropertiesMap = extend(Object.create(null), { $attrs: i => (__DEV__ ? shallowReadonly(i.attrs) : i.attrs), $slots: i => (__DEV__ ? shallowReadonly(i.slots) : i.slots), $refs: i => (__DEV__ ? shallowReadonly(i.refs) : i.refs), - $parent: i => i.parent && i.parent.proxy, + $parent: i => getPublicInstance(i.parent), $root: i => i.root && i.root.proxy, $emit: i => i.emit, $options: i => (__FEATURE_OPTIONS_API__ ? resolveMergedOptions(i) : i.type),