Reputation: 8167
I need to pass an object to a child slot, but that object will not be ready when the component is mounted and it absolutely cannot be a reactive because webpack will do bad things, even when it's a shallow reactive.
Short version: I got the google maps api (googlemaps/js-api-loader) all wired up with markers and clustered, and worked out all the bugs. Now I want to turn it into components and reuse it.
It was easy enough to wait for the map to be ready when it was all one component, but now I have markers in separate components (to allow easy layering/separate control of marker groups). Per the link above, I cannot make the map object reactive. However, the initial state is passed into children via properties, so it's always undefined
.
Map component:
<template>
<div class="map" ref="mapDiv"></div>
<slot name="markers" :map="map" v-if="mapped"></slot>
</template>
Script setup()
:
const mapDiv = ref();
const mapped = ref(false);
let map;
new Loader(props.loader).load().then((result) => {
map = new window.google.maps.Map(mapDiv.value, props.options);
mapped.value = true;
return result;
});
return {mapDiv, map, mapped}
I thought to add the v-if
and see if it would grab the latest value, but that still uses the initial undefined value of map that was returned. Which makes total sense.
Massive workaround, I can shove the reference in the global window object and poll, but that breaks the Vue pattern. I also need a per-instance reference of the map object, as there may be multiple map components, which becomes a juggling nightmare.
The Question
Is there a way to pass a non-reactive property within the Vue component setup? Even a way to pass it as a delayed action?
Deeper explanation:
Vue wants us to do this:
const mapDiv = ref();
const map = reactive({});
new Loader(props.loader).load().then((result) => {
map.assign(new window.google.maps.Map(mapDiv.value, props.options));
return result;
});
return {mapDiv, map}
But the moment you shove the map in a reactive, Vue explodes in errors. The map object is not compatible with the reactive proxy. Even with a shallowReactive
, it tries to traverse properties that point to cross-site resources from google, which is a security issue: the browser has a meltdown and it just doesn't work.
As an example, this works as expected:
const mapDiv = ref();
const map = reactive({}); //<-- WORKS BECAUSE REACTIVE
new Loader(props.loader).load().then((result) => {
Object.assign(map, {test: 'Hello, world!'});
return result;
});
return {mapDiv, map}
Upvotes: 0
Views: 1599
Reputation: 8167
It's not necessary to use reactive for an object unless what your really need is reactivity. For basic awareness of the object change passed down to child components, a ref
or shallowRef
will do:
const map = ref({});
map.value = new window.google.maps.Map(mapDiv.value, props.options);
Upvotes: 1