DEV Community

Cover image for New Suspense Hooks for Meteor
Gabriel Grubba
Gabriel Grubba

Posted on • Edited on • Originally published at blog.meteor.com

New Suspense Hooks for Meteor

New Suspense hooks for Meteor

As we learned in the previous part of this series, why and how we could use Suspense. This article will discuss and show how to use Meteor's newly added suspendable hooks.

With the changes coming to Meteor, especially with its fibers-free future, we decided to add to our hooks collection react-meteor-data a few hooks that can deal with those new async methods.

For starters, we need to address that useFind still works as it always did on the client;
it was implemented using synchronous functions, so it was safe from change. But important to note that if you are using the useFind hook on the server, for example, while using SSR, you will need to use the newly added suspense/useFind hook. This is important because now you cannot do a sync database search with the current implementation of useFind in the server, but with the newly added Suspense version, you can.

Before showing examples, we would like to show another made-suspendable hook: useSubscribe now. Instead of using an isLoading function to know when the subscription is ready, we made it use the Suspense API. Let's look at how it was before and how it will be:


// before
// Tasks.jsx
function Tasks(){
    const [hideDone, setHideDone] = useState(false);
    const isLoading = useSubscribe("tasks");
    const filter = hideDone ? { done: { $ne: true }  } : {  };
    const tasks = useFind(
        () => TasksCollection.find(filter, { sort: { createdAt: -1 } }),
        [hideDone]
    );

    if (isLoading()) return <Loader />

    // render the tasks
}

// With suspense
// Tasks.jsx (have a Suspense wrapper outside with fallback={ <Loader /> }
function Tasks(){
    const [hideDone, setHideDone] = useState(false);
    useSubscribe("tasks");
    const filter = hideDone ? { done: { $ne: true }  } : {  };
    const tasks = useFind(
        TasksCollection,
            [filter, { sort: { createdAt: -1 } }],
        [hideDone]
    );

    // render the tasks
}
Enter fullscreen mode Exit fullscreen mode

It looks and feels almost the same. We just moved the isLoading to the outside, and now we have a much more declarative code with a better Developer experience.

The changes regarding the useFind are how you build your function. Now you should pass the Collection, the arguments, and its dependencies.

What about useTracker?

In this part, there will be a change to suspend when async. This is due to how Suspense works under the hood(a simple explanation: we need a way to track the promises when they are thrown, for a longer version, check the previous article from this series ). One of the things we will need to add one key to each useTracker instance.

// before
// Tasks.jsx

function Tasks(){
    const isLoading = useSubscribe("tasks");
    const { username } = useTracker(() => Meteor.userAsync())
    const tasksByUser = useTracker(() => 
             TasksCollection.find({username}, { sort: { createdAt: -1 } }).fetch()
    );

    if (isLoading()) return <Loader />

    // render the tasks
}

// With suspense
// Tasks.jsx (have a Suspense wrapper outside with fallback={ <Loader /> }
function Tasks(){
    useSubscribe("tasks");
    const { username } = useTracker("user",() => Meteor.userAsync()) 
    const tasksByUser = useTracker("tasksByUser", () =>
         TasksCollection.find({username}, { sort: { createdAt: -1 } }).fetchAsync() // fetch will be async
    );

    // render the tasks
}

Enter fullscreen mode Exit fullscreen mode

It seems more bloated due to the addition of strings, but now we do not need to think about loading states, and for some of them, the new react rendering engine improves our performance, and the reactivity is maintained between renders.

Why are these changes so significant?

If, in your case, you only used useFind as before, without SSR and without using useTracker with async dependencies such as calling a fetch from a collection, then you may not need to update as these changes are just new API areas for solving the newly added functionalities that were added in Meteor 3.

Top comments (0)