I stumbled into a totally unexpected problem while refactoring my code to composition API: there doesn't seem to be any (documented) way of accessing current instance from the lifecycle hooks.
sample code:
import { defineComponent, onMounted } from 'vue';
export default defineComponent({
setup() {
onMounted(() => {
console.log(this); // <-- will be undefined
});
},
mounted() {
console.log(this); // <-- will be the component
},
}
I've spent hours trying to find a solution to this and ultimately just used the old options API to get what I want. None of examples, tutorials or documentation - that I read - use this
in the hooks.
But I find it unbelievable that only undocumented getCurrentInstance
would be the way to get the current instance from the hook.
So, which doc did I miss?
UPDATE 2.
You can mix Composition API
and Options API
to access this
, if you need it.
Using this
in Options API
you can access all objects defined inside setup
like variables, methods, computed, refs and etc.
But you cannot access anything defined using Options API
inside setup
.
The data
provided over Options API
is mixed with the data from setup
. The objects from setup
overwrite the definitions provided over Options API
.
See how Vue mixes the data
properties in the following example.
const { createApp, ref } = Vue;
const MyComponent = {
setup() {
// there is no way to access the `optionsVar` inside the `setup`
const setupVar = ref('setupVar content')
const collisionVar = ref('content from setup')
const collisionObj = ref({ setup: true })
return { setupVar, collisionVar, collisionObj }
},
data() {
return {
optionsVar: 'optionsVar content',
collisionVar: 'content from data()',
collisionObj: { options: true }
}
},
methods: {
log() {
console.log(`setupVar: ${this.setupVar}`)
console.log(`collisionVar : ${this.collisionVar}`)
console.log(`collisionObj: ${JSON.stringify(this.collisionObj)}`)
}
},
template: `<button type="button" @click="log()">log()</button>`
}
const App = {
components: {
MyComponent
}
}
const app = createApp(App)
app.mount('#app')
<div id="app">
<my-component />
</div>
<script src="https://unpkg.com/vue@3/dist/vue.global.prod.js"></script>
UPDATE 1.
Here is the same example with a component
const { createApp, ref, onMounted } = Vue;
const MyComponent = {
setup() {
const id = ref(Math.round(Math.random() * 100000));
const count = ref(0);
const plus = () => { count.value++; }
const minus = function() { count.value--; }
onMounted(() => {
count.value = Math.round(Math.random() * 10)
});
return {id, count, plus, minus }
},
template: `id: {{id}} <button type="button" @click="minus()">-1</button>
{{count}}
<button type="button" @click="plus()">+1</button><hr/>`
}
const App = {
components: {
MyComponent
}
}
const app = createApp(App)
app.mount('#app')
<div id="app">
<my-component v-for="i in 5" />
</div>
<script src="https://unpkg.com/vue@3/dist/vue.global.prod.js"></script>
What for do you need this
in the component?
If you create your component with Composition API, then you can access all the properties directly, without using this
.
Here is a very basic example:
const { createApp, ref, onMounted } = Vue;
const App = {
setup() {
const count = ref(0);
const up = () => { count.value++; }
const down = function() { count.value--; }
onMounted(() => {
count.value = 10
});
return {count, up, down }
}
}
const app = createApp(App)
app.mount('#app')
<div id="app">
<button type="button" @click="down()">-1</button>
{{count}}
<button type="button" @click="up()">+1</button>
</div>
<script src="https://unpkg.com/vue@3/dist/vue.global.prod.js"></script>