]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(runtime-core): skip functional components in public $parent chain traversal
authorEvan You <yyx990803@gmail.com>
Fri, 27 Nov 2020 15:10:25 +0000 (10:10 -0500)
committerEvan You <yyx990803@gmail.com>
Fri, 27 Nov 2020 15:10:25 +0000 (10:10 -0500)
fix #2437

packages/runtime-core/src/componentPublicInstance.ts

index 2ac9b8a47a1edb60317e8803c400d58d4002af50..1e62f8b16c55c740d375730dfa73193933b9feb8 100644 (file)
@@ -200,6 +200,16 @@ export type ComponentPublicInstance<
 
 type PublicPropertiesMap = Record<string, (i: ComponentInternalInstance) => 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),