Just on the subject of vue-meteor-tracker
, I remembered before Akryum released the updated vue-meteor-tracker for Vue 3, I already had a proof of concept for the Vue 2 version of the composition API (back in the RFC days) using Tracker, ReactiveVar and ref/reactive from Vue.
(It is gross, mixed with (deprecated) business code, and causes some errors with recent updates of Vue, so I won’t share it here)
Since then I’ve mostly used Tanstack Query, but I experimented a bit more later on with some useSubscription/useTracker
composables/hooks at some point, and I’ve just had a review of @vooteles’ code and tried to think about how it could be turned into a hook, so I’ve quickly regurgitated all of that information and come up with this (untested) draft idea, where I’m trying to have the lightest-touch approach possible while keeping the two reactivity systems synced up:
import { Meteor } from 'meteor/meteor'
import { Tracker } from 'meteor/tracker'
import { ReactiveVar } from 'meteor/reactive-var'
import { ref, watch, reactive, set, computed, type Ref, onUnmounted, WatchSource } from 'vue'
export function useTracker<T>(source: WatchSource, query: () => Promise<T> | T) {
const data = ref<T | undefined>()
const error = ref<any>()
const hasError = ref<boolean>(false)
const tracker = Tracker.autorun(() => {
try {
// Ideally some Mongo.Collection query goes here
Promise.resolve(query())
.then(result => {
data.value = result
hasError.value = false
error.value = undefined
})
.catch(e => {
console.error(e)
hasError.value = true
error.value = e
})
} catch (e) {
console.error(e)
hasError.value = true
error.value = e
}
})
watch(source, () => {
tracker.invalidate()
})
onUnmounted(() => {
tracker.stop()
})
return {
data,
hasError,
error,
}
}
export function useSubscription(key: string, params?: Ref<any[]>) {
return useTracker(params ?? ref(), () => {
Meteor.subscribe(key, ...params?.value ?? [])
})
}
So then you’d use it like:
<script setup lang="ts">
import { useTracker, useSubscription } from '/imports/hooks/meteor'
useSubscription('admin.users.all')
const {
data: users,
error: usersError,
hasError: usersHasError
} = useTracker(() => Meteor.users.find({ ... }).fetch())
//...
</setup>
<template>
<WarningMessage v-if="usersHasError">
{{ String(usersError) }}
</WarningMessage>
...
</template>
I noticed there’s still a bit of a difference between our approaches @vooteles, so I wanted to know if I was missing anything critical that you found when testing on your end.
Particularly worried with potential conflicts with multiple subscriptions supplying the same collection with data.
The other thing I noticed reviewing the source code for Akryum’s vue-meteor-tracker is that it seems much more in-depth than what I’ve got above. I’m not sure what I’m missing out on if that’s the case.
(I need to start a new Meteor 3 Vue project to try this out, my two Meteor 3 projects are an in-progress update from Meteor 2 to 3 with lots of Tanstack Query, and a React project )