useTracker and *Async Meteor collection methods

I am in the process of migrating my app to use findOneAsync etc. and I cannot find a reference on how to handle client calls within useTracker. It seems useTracker does not handle promised computations. Is this going to be part of Meteor 2.11?

Also it seems applyAsync is private in @types/meteor?! Can we safely use that one?

2 Likes

Hello @superfail, regarding types, we have been moving our types to the core: Using Core Types | Meteor API Docs I will check on that, but you can use applyAsync but note that it returns a Promise

In the matter of migrating, I have a question. In your case, if you are making a query for a find in the DB, using a useFind would not make more sense in this case? react-packages/packages/react-meteor-data at master · meteor/react-packages · GitHub

If you can share a generic code snippet, we can use it, and it may even help more people!

Hi @grubba!

Yes I am already using useFind where it makes sense. Here I am talking about cases where only Collection#findOneAsync makes sense. Is there a way to make findOneAsync work with useTracker today? Is it just an oversight in @types/meteor that promises are not allowed (they seem to be allowed in Tracker.autorun)?

Thanks, I will look into zodern:types. Why does it look like it still requires @types/meteor?

About applyAsync, does it really return a promise? From the docs and @types/meteor, it seems it accepts an “asyncCallback”.

I guess one could abuse useFind by limiting to the first result. What about Meteor.user(), Meteor.status() etc.? Are those going to remain synchronous?

One of the patterns I want to continue using in the future is the following:

const isLoading = useSubscribe(...);
const loading = isLoading();

const item = useTracker(() => loading ? undefined : Collection.findOne(...), [loading, ...]);

const found = Boolean(item);

return {loading, found, item};

This requires having a synchronous implementation of findOne to avoid invalid transient states. As hinted at here react-packages/useFind.ts at d0645787dac675bbf5412cac0da9387b6315f5c4 · meteor/react-packages · GitHub one can rely on the synchronous behavior of Cursor#observe on initialization to implement fetchSync and findOneSync. But is this the only way? Is this recommended? Should we use different patterns? Will Meteor provide a fetchSync and findOneSync function to ease the transition?

Is there any Documentation out now how to handle useTracker Async, e.g.

const Component = () => {
    const user = useTracker(async () => Meteor.userAsync()) // will return a Promise we have to await!
    // If we "await"/use async, then the Component gets async, which does not work!
}

I link here useTracker + React Suspense:

But I don’t get it. Doesn’t useTracker return a promise in the examples, we need to await?

EDIT: React Suspense Use Tracker can resolve a promise, it seems, we can work with this pattern. :slight_smile:

1 Like

Hey @sebastianspiller ! actually what it does is resolve this promise in a way that react understands(using suspense).

in your example, what we can do is this:

import { useTracker } from 'meteor/react-meteor-data/suspense'
function Tasks() { // this component will suspend
  const { username } = useTracker("user", async () => await Meteor.userAsync())
///
}

const App = () => {
  return (
   <div>
     <h1> Hello from our app </h1>
     <Suspense fallback={<Loading />}>
          <Tasks />
      </Suspense>
   </div>
  )
}

react docs are pretty good at explaining how to use this feature

3 Likes

Wow, maybe <Suspense> + error boundaries is the solution then? Instead of ad-hoc handling of loading/error state.