Vue.js refs are undefined, even though this.$refs shows theyre there
I solved this by using v-show instead of v-if.
I had the component inside a v-if statement.
<div v-if="!isLoading">
<GMap ref="mapRef" />
</div>
I just changed that to v-show
<div v-show="!isLoading">
<GMap ref="mapRef" />
</div>
And now the object is available in mounted(). Still find it strange that the console.log(this.$refs) showed it being available as a key on this.$refs, even though it actually wasn't? Thats strange behaviour.
The other wierd thing was, that even if I tried to access this.$refs.mapRef in my data loading section, AFTER THE DATA WAS LOADED, (ie after isLoading=false), I still couldn't access it. Even though then, it should've been available because the v-if passed.
So v-show solved it, by just hiding the div, instead of not rendereding it. Stupid little workaround.
Main solution is to make sure your component is not imported dynamically
You'd still need to also avoid wrapping your component with v-if
and use this.$refs.mapRef
in mounted()
, instead of created()
I wasn't using Vue Google Maps plugin/component, but my own custom component
Method 1
Use:
import CustomComponent from './CustomComponent ';
export default {
components: {
CustomComponent,
},
...
}
Instead of
export default {
components: {
CustomComponent: () => import('./CustomComponent'),
},
...
}
Method 2
Use this.$refs.mapRef
in mounted()
instead of created()
.
This way, setTimeout()
and this.$nextTick()
not needed
Correct way:
mounted(){
//works! child components were loaded
console.log(this.$refs.mapRef)
}
Wrong way:
created(){
//DON'T DO THIS! child components hasn't loaded
console.log(this.$refs.mapRef)
//might work but it's an unreliable workaround
setTimeout(()=>{
console.log(this.$refs.mapRef)
}, 0);
//might work but it's an unreliable workaround
this.$nextTick(()=>{
console.log(this.$refs.mapRef)
});
}
Method 3
Do not wrap child component using v-if
, use v-show
instead.
Correct way:
<div v-show="!isLoading">
<GMap ref="mapRef" />
</div>
Wrong way:
<div v-if="!isLoading">
<GMap ref="mapRef" />
</div>
Other Methods (not proper & not a solution)
The following are methods I tried but didn't work until I used the methods on top (stopped using dynamic import)
I already put this.$refs.mapRef
in mounted()
tried to wrap it with setTimeout()
and 2 layers of this.$nextTick()
.
It works only on hot reload, but no longer works after a page refresh
mounted(){
setTimeout(()=>{
this.$nextTick(()=>{
this.$nextTick(()=>{
console.log(this.$refs.mapRef) // returns undefined
});
});
}, 0);
}
Thanks to this comment in another answer: How to access to a child method from the parent in vue.js
I had a similar problem getting a ref to a leaflet map instance, try waiting for the "nextTick"
mounted(){
this.$nextTick(()=>{
let self = this
console.log(self.$refs) // Shows the mapRef object reference
console.log(self.$refs.mapRef) // returns undefined ???
});
}
see the docs for more- https://v2.vuejs.org/v2/api/#vm-nextTick and https://v2.vuejs.org/v2/api/#mounted