Hi guys,
I guess many of you already were in the same situation, that you need to load data not only from subscriptions, but also via Meteor.call. A very elegant way would be to have all this data-fetching in one place in the withTracker
HOC.
I have fiddled around with it but it seems to always break the component - one big problem is the loading
prop, which I usually define as const loading = !sub.ready()
- has anyone found a solution to also use Meteor.call
inside the withTracker
HOC?
Solving it via componentDidUpdate()
is very tedious because of needing to check if the props have changed and all that stuff.
Thanks, cheers
Patrick
I solved this with using state. Once the data is retrieved I push it into state.
You should not use Meteor.call
inside a computation, because it will get invoked every single time the computation updates, which can happen at indeterminate intervals, and possibly even every time the component renders (if you don’t supply deps
).
Instead, if you want to keep things coupled, you could compose your hooks, into another hook:
const useMyCustomHook = (query) => {
// useTracker first if we are using that data for our method call
const trackerData = useTracker(() => {
const sub = Meteor.subscribe('my-pub', query)
const data = MySubCollection.find({}).fetch()
return {
data,
isLoading: !sub.ready()
}
}, [query]) // set deps as appropriate (or not, it's not required)
// state for your method
const [methodData, updateMethodData] = useState(null)
// call method in useEffect
useEffect(() => {
// if we don't have the necessary data, just return void or null
if (trackerData.isLoading) return null
// if we are loaded, but don't have expected data, throw
if (!trackerData.data[0]?.whatever) throw new Error('whatever')
// call the method with data from the trackerData
Meteor.call('some-method', trackerData.data[0].whatever, (err, res) => {
if (err) {
console.error(err) // or throw, or whatever
return
}
// update the methodData state, and re-render
updateMethodData(res)
})
}, [trackerData.data.isLoading, trackerData.data[0].whatever) // set deps as appropriate (required) - if we rely on data from tracker, we pass that here
return {
methodData,
trackerData
}
}
Now you can call useMyCustomHook(query)
wherever you need this set of data. This sort of functional composition is what makes hooks so grand.
2 Likes