I have a bootstrapped Meteor 3 project (meteor create --vue my-app --release=3.0.1
), using Vue 3 (written in composition API style) along with vue-meteor-tracker
package (GitHub - meteor-vue/vue-meteor-tracker: Use Meteor Tracker reactivity inside Vue components). My application is currently structured as described in Meteor guide (Application Structure | Meteor Guide), specifically, my ui
directory looks like this:
-/imports/ui
|-App.vue // app layout with header, footer and content handled with <RouterView />
|-main.js // app entrypoint
|-router.js // routes definitions
|
|-components // simple components (e.g. layout elements or other DOM fragments)
| |-Footer.vue
| |-Header.vue
| |-...
|
|-views // pages/views (used in router.js routes definition)
| |-HomeView.vue
| |-OtherView.vue
| |-...
I’m struggling to understand how exactly to subscribe and track MongoDB data with vue-meteor-tracker
to have it available in all my views (pages) or components.
If I understood the logic behind subscribing to and tracking the data, it works like this:
- if I subscribe to a collection in
HomeView.vue
, I won’t be able to track this data inOtherView.vue
(unless I re-subscribe there again) - if I subscribe to a collection in
App.vue
, I’ll be able to track the data in all my views and components - if I subscribe to a collection in
App.vue
, I’ll be able to track the data in all my views and components in different ways if I need to (e.g. use one MongoDB query inHomeView.vue
and a different query inOtherView.vue
)
I’d really like to know if these “assumptions” are correct to begin with?
Now, let’s say I have a specific query which I’d like to use in multiple views or components. To avoid writing the same query multiple times in my views/components, I did the following:
- I subscribed to my collection in
App.vue
- I created a new file
/imports/ui/trackers.js
- in
trackers.js
I wrote my query/queries and exported them:
import { autorun } from 'vue-meteor-tracker';
import { MyCollection } from '../api/MyCollection';
export const myCollection = autorun(() => MyCollection.find().fetch()).result;
- wherever I need this data, I simply import the variable from
trackers.js
:
// e.g. `OtherView.vue`
<script setup>
import { myCollection } from '../trackers';
</script>
<template>
<div>Collection size: {{ myCollection.length }}</div>
<div v-for="item in myCollection">{{ item.name }}</div>
</template>
As far as I can tell, this works fine, I can see myCollection
data as expected.
However, with this approach, I’m getting a warning in browser’s console:
[trackers.js] 'autorun()' should only be used in setup() inside components to clean up correctly. If you need to call 'autorun' later outside of the setup context, use 'useAutorun()' instead.
If I change my code to use useAutorun()
, as suggested in the warning message, and change the code in trackers.js
to this:
import { useAutorun } from 'vue-meteor-tracker';
import { MyCollection } from '../api/MyCollection';
const { autorun } = useAutorun();
export const myCollection = autorun(() => MyCollection.find().fetch()).result;
I can still use my data “as expected” and everything seems to work fine again. But now I see a different warning message in browser’s console:
[trackers.js] [Vue warn]: onUnmounted is called when there is no active component instance to be associated with. Lifecycle injection APIs can only be used during execution of setup(). If you are using async setup(), make sure to register lifecycle hooks before the first await statement.
Given that I see these warnings whichever method I use to track my data with vue-meteor-tracker
, I think I’m doing something wrong here.
My questions are actually very simple – am I understanding subscription/tracking logic correctly and what would be “the correct” way to structure my app to be able to write queries which I could use in any view/component?
Thank you very much in advance!