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