21

I'm running into an issue with Vue 3 (alpha 4):

Inside the setup() function I am trying to read the parent component. As per the documentation on https://vue-composition-api-rfc.netlify.com/api.html#setup it should expose the parent via the context argument, either as a property of context.attrs or directly as parent (see the SetupContext bit under 'typing'). I don't find the documentation to be very clear on whether parent should be accessed directly from SetupContext, or via SetupContext.attrs, so I've tried both ways, but to no avail.

Here's my issue, I can access the SetupContext and SetupContext.attrs (which is a Proxy) just fine when logging them. SetupContext.attrs exposes the usual proxy properties ([[Handler]], [[Target]] and [[IsRevoked]]) and when inspecting [[Target]] it clearly shows the parent property.

When logging the parent though, it just prints out undefined:

export default {
  setup(props, context) {
    console.log(context);
    // Output: {attrs: Proxy, slots: Proxy, emit: ƒ}
    console.log(context.attrs);
    // Output: Proxy {vnode: {…}, parent: {…}, appContext: {…}, type: {…}, root: {…}, …}
    console.log(context.attrs.parent);
    // Output: undefined
  }
};

Spreading the context yields the same result:

export default {
  setup(props, { attrs, parent }) {
    console.log(attrs);
    // Output: Proxy {vnode: {…}, parent: {…}, appContext: {…}, type: {…}, root: {…}, …}
    console.log(attrs.parent);
    // Output: undefined
    console.log(parent);
    // Output: undefined
  }
};

I'm a bit new to proxies in JavaScript, but from what I've read on them, and from experimenting with proxies returned by reactive() for example. I should just be able to access the property like I normally would with an object. Any ideas on what I'm doing wrong?

I've created a codesandbox to reproduce the problem

Jason Aller
  • 3,541
  • 28
  • 38
  • 38
TdeBooij
  • 212
  • 1
  • 2
  • 6
  • 1
    If you see a `parent` property in `attrs` but `attrs.parent` is undefined, then it is because `attrs` is filled after you log it. You could try to put your code in a `onMounted` hook. – Paleo Feb 18 '20 at 07:47
  • Good suggestion @Paleo, I've just tried it but even in onMounted() both are undefined unfortonately. – TdeBooij Feb 18 '20 at 21:08
  • I have the same problem here, unable to access the Proxy object's target in my App component https://github.com/blacksonic/todomvc-vue-composition-api/blob/master/src/components/app/app.vue – VuesomeDev Apr 05 '20 at 20:33
  • Have a look [here](https://stackoverflow.com/questions/58579884/how-to-access-root-context-from-a-composition-function-in-vue-composition-api) and [here](https://stackoverflow.com/questions/60202724/vue-3-composition-api-and-access-to-vue-instance) – DarkLite1 May 07 '20 at 15:54

2 Answers2

22

You can use getCurrentInstance. It is undocumented Vue feature.

Usage is as easy as:

import { getCurrentInstance } from "vue";
export default {
  setup(props) {
    const instance = getCurrentInstance();
    console.log("parent:");
    console.log(instance.parent);
  }
}

Vue considers it an internal api and warns against using it. For your consideration, you can read this github issue and this documentation from wayback machine.

Also, probably worth noting that Vue composition api plugin exposes parent in the same way, but it is referenced as instance.$parent there.

Heniker
  • 589
  • 6
  • 13
  • 1
    The link to the documentation doesn't work – Maurici Abad Mar 16 '22 at 15:46
  • 3
    New Vue wiki does not have article about `getCurrentInstance` for some reason. It is still available for use though. – Heniker Mar 17 '22 at 16:57
  • 1
    And when you want to access a data property from the parent you have to access the proxy object of the parent instance like so: `instance.parent.proxy.myVarName` – Niwo Mar 22 '22 at 21:44
  • 1
    In case someone wants to read what was in that wiki page - [Wayback Machine](https://web.archive.org/web/20220207001110/https://v3.vuejs.org/api/composition-api.html#getcurrentinstance) – Heniker Jun 13 '22 at 22:12
  • `getCurrentInstance` is an internal API and it's usage is discouraged https://github.com/vuejs/vue/issues/12596#issuecomment-1173269807 It can give you issues in a production build versus a dev build. – Walter Montes Oct 07 '22 at 16:03
  • 1
    It really can't give issues in production build, as e.g. `vue-router` uses it. But yeah, caution and reading links above is advised. I updated post with this information. – Heniker Oct 22 '22 at 00:22
6

I know this doesn't answer the question directly, but using provide/inject (https://v3.vuejs.org/guide/component-provide-inject.html) has helped me resolve this same issue where I wanted to get a data attribute from the parent node and to pass it to the rendered component, but could not access the parent anymore after upgrading from Vue2 to Vue3. Rather than trying to expose the parent, I passed a prop from its dataset down to the rendered component.

Upon creating the app, I did the following.

main.js

import { createApp } from "vue";
import MyComponent from './components/MyComponent.vue';

const section = document.getElementById('some-element'); // this element contains a data-attribute which I need to use within the app. In my case, I can't get the data from the component created/mounted function as the section with the data attribute is loaded onto the page multiple times with different attributes each time.

const app = createApp(MyComponent);
    app.provide('dataset', section.dataset.id); // section.dataset.id contains some kind of id, let's say 'abc123' for the sake of this example
    app.use(store); //not relevant for this answer
    app.mount(section);

Then, inside the component, I could access the 'dataset' by doing the following.

MyComponent.vue

<template>
    <div>Normal template stuff here</div>
</template>
<script>
export default {
    name: 'MyComponent',
    inject: ['dataset'], // the magic
    created() {
        console.log(this.dataset); // will log 'abc123'
    }
}
</script>

This is very stripped down, but shows my case nicely i guess. In any case, if you're trying to do something similar and want to get data via parent data attribute, you could look into provide/inject.

Hope it helps anyone out there!

rubeus
  • 71
  • 1
  • 4
  • Problem is you have no way of knowing the injected thing came from, exactly, the parent, which you may want to know. – spinkus Jul 19 '23 at 23:44