I have following scenario. I have this component
<div class="flex items-start gap-4">
<div class="flex w-full flex-col gap-4">
<div class="border shadow p-2">
<chart :config="lineConfig" ref="linechart" />
</div>
</div>
<options
:chart="$refs.linechart"
:resolution="lineResolution"
:maxTicksLimit="lineMaxTicksLimit"
></options>
</div>
In my options.vue
export default Vue.extend({
props: ['resolution', 'maxTicksLimit', 'chart'],
watch: {
resolution() {
this.chart.update()
},
maxTicksLimit() {
this.chart.update()
},
},
created() {
setTimeout(() => {
console.log(this.chart)
}, 100)
},
})
I always gets undefined. I understand that the component did not mounted yet and i would need to use $nextTick(), but if i pass :chart="$refs" then i see in the console { linechart: ... }
Also a sidenote: If i interact with the chart, for example using chart.update(), then this.chart is no more undefined.
My goal is to pass the chart with $refs.linechart so i can use the methods of the component
From Vue docs
An important note about the ref registration timing: because the refs themselves are created as a result of the render function, you cannot access them on the initial render - they don’t exist yet! $refs is also non-reactive, therefore you should not attempt to use it in templates for data-binding.
So that explains pretty much the entire behaviour. If you are binding $this.linechart it will pass undefined at first render because the ref doesn't exist yet. If you are binding $refs you pass a reference to $refs object which latter is updated in a non-reactive way.
I can think only of one solution. Render the options component only after the parent has been rendered, to have $refs object populated, and don't count on its reactivity. Like:
<options
v-if="rendered"
:chart="$refs.linechart"
:resolution="lineResolution"
:maxTicksLimit="lineMaxTicksLimit"
></options>
data(){
rendered: false
},
mounted() {
this.$nextTick(() => this.rendered = true)
}