I am trying to access a template ref from a deeply nested children. I have three components, SecondLayer.vue, HelloWorld.vue and Calendar.vue. I want to provide childrenRef
from SecondLayer.vue
and access it in Calendar.vue
via inject.
In SecondLayer.vue
:
<template>
<div ref="childrenRef">
This is from the second layer HEADER
<slot name="header"></slot>
This is the from second layer MAIN. The price is: {{ test }}
<slot name="main"></slot>
</div>
</template>
<script setup>
import { inject, provide, ref, onMounted } from "vue";
const test = inject("price");
const childrenRef = ref(null);
const test1 = ref("TEST1");
console.log(childrenRef.value);
// provide("childrenRef", childrenRef.value);
provide("test1", test1.value);
onMounted(() => {
console.log(childrenRef.value);
provide("childrenRef", childrenRef.value);
});
console.log(test);
</script>
In HelloWorld.vue
:
<template>
<div class="greetings">
<second-layer>
<template #header>
<button>A button for the header</button>
</template>
<template #main>
<button>A button for main</button>
<Calendar/>
</template>
</second-layer>
<h1 class="green">{{ msg }}</h1>
<h3>
You’ve successfully created a project with
<a href="https://vite.dev/" target="_blank" rel="noopener">Vite</a> +
<a href="https://vuejs.org/" target="_blank" rel="noopener">Vue 3</a>. What's next?
</h3>
</div>
</template>
In Calendar.vue
:
const childrenRef: any = inject("childrenRef");
const test1: any = inject("test1");
watch(childrenRef, newVal => {
console.log(newVal);
})
onMounted( async () => {
selectedDaysInMonth.value = daysInMonth(selectedYear, selectedMonth);
await nextTick();
console.log(test1);
console.log(childrenRef);
})
In the onMounted
of SecondLayer
I can see children.ref
showing the div.
In the onMounted
of Calendar
I can see test1
being logged as TEST1
but childrenRef
is logged as null
. This is where I don't understand. I've ensured it's provided when the SecondLayer
component is mounted and that's when I provide childrenRef
, why is it that the Calendar
component sees it as null
?
Can someone explain what I am doing wrong or misunderstanding?
The problem that you provide an unwrapped ref value which is undefined
at the moment of calling provide
.
Rather provide the ref itself:
provide("childrenRef", childrenRef);
Then you will be inject this ref and use it as a ref. Providing the DIV element wouldn't work since it's not available at the time the setup function is called. Moreover Vue can re-render and recreate HTML with another DIV for various reasons (introduced later for example) and you will have an invalid (old) DIV. So use a reference.
In the Calendar.vue you get your DIV: