I am currently working on a component where I pass the reference to an internal element to the parent using defineExpose
. In this example, I simply log the element, but in my actual project, I intend to manipulate it.
// Comp.vue
<script setup>
import { ref } from 'vue'
const el = ref(null);
defineExpose({ inner: el });
</script>
<template>
<p ref="el">My Element</p>
</template>
// App.vue
<script setup>
import { nextTick, onMounted, ref } from 'vue'
import Comp from './Comp.vue'
const myRef = ref(null);
function logMe() {
console.log(myRef.value);
}
onMounted(async () => {
//await nextTick(); <-- This solves the problem
logMe();
});
</script>
<template>
<button @click="logMe">Log the element</button>
<Comp :ref="(el) => {myRef = el ? el.inner : undefined}" />
</template>
I recently discovered that in Vue, child components are mounted before their parents. So, when I try to access myRef
after the parent is mounted, it still returns as null
.
The solution to this issue is to wait for the next tick. However, what puzzles me is why these operations aren't completed synchronously during mounting, and why waiting for the next tick ensures that everything is executed properly, even though they are internally asynchronous operations.