Your Web News in One Place

Help Webnuz

Referal links:

Sign up for GreenGeeks web hosting
March 20, 2023 01:35 pm GMT

Making Promises Suspendable

Making Promises Suspendable

This is a two-part article in which we focus first on understanding the foundations of the reasons to use the Suspense API, and in the next part, we will discuss how to use the New Suspense hooks for Meteor

I will explain how to make your promises go into suspense mode and what it takes to get there.

I recommend two articles for theory on this side that helped me understand how React deals with async values. One is from Dan Abramov - Algebraic Effects for the Rest of Us, and the other is from Radosaw Miernik - Onthrowin React

Why use suspense?

As this good article explains, Suspense gives us two great features:

  • Declarative code witch means that React Suspense simplifies the process of writing UI code by allowing developers to declare what they want the UI to look like rather than writing code that tells the UI how to render step-by-step. One example of this feature is the removal of the use isLoading variable. By placing this variable above the UI code, developers can ensure that their code is in sync with the UI. This eliminates the need for awkward if statements.
  • Better end-user experience with Suspense. You can use the newly added concurrent rendering engine in React. This Suspense feature gives the end user a better feeling of how the UI looks and acts because react only will update what it needs.

Theory aside, here ismy gist, which is why this article exists. You can use thisplayground as well.

Now I will explain how this works. First, you will need a cache map to store your promises. As React suspends, the promise and then fulfills it, you need a way to track this specific promise (this was a part that I struggled with a lot to understand, it has to be the exact same promise each time). If there is no value in the given key, the hook will create an entry in the map with this promise and throw it. Here is where the magic happens. The suspensify hook looks like the snippet below in its first run:

function suspensify<T>(key: string, promise: Promise<T> | null, deps: DependencyList = [], lifespan = 0): T {  const cached = cacheMap.get(key)    **//     this is undefined. all code below is not ran  /* ... code ...*/ const entry: Entry = {    deps,    promise: new Promise((resolve, reject) => { // here you work in your promise / waitable value. remember to set the result and error      promise        .then((result) => {          entry.result = result          resolve(result)        })        .catch((error) => {          entry.error = error          reject(error)        })    })  }  cacheMap.set(key, entry)  throw entry.promise// this is where we jump into the fallback}

Before we talk about the return side of the suspense API, I would like to point out that when you pass in a null value is the same as saying that you want it to return null and not run the hook, as we cannot put an if statement above a hook, this is the way to deal with control flow.

Well, when the hook runs again (yes, that is how suspense works), we will go to the if that was above the entry creation:

function suspensify<T>(key: string, promise: Promise<T> | null, deps: DependencyList = [], lifespan = 0): T {  const cached = cacheMap.get(key)  //     now we have a value here  useEffect(() =>    () => {      setTimeout(() => {        if (cached !== undefined && isEqual(cached.deps, deps)) cacheMap.delete(key)                // clean when the hook unmounts.      }, lifespan)    }, [cached, key, ...deps])  if (promise === null) return null // we talked about this one  if (cached !== undefined) {    if ('error' in cached) throw cached.error                                                        // trigger error boundary    if ('result' in cached) {      const result = cached.result as T      setTimeout(() => {        cacheMap.delete(key)      }, lifespan)      return result // resolve suspense    }    throw cached.promise // as we have not got any result or err we should wait a bit more  }/* ... code ...*/}

There are some caveats. We need to address that setTimeout that works as defer they are necessary because after we return the value of the promise, we need to clean this key, as it may be required to run another code when this component mounts again. You can adjust the lifespan if you want to reuse the same value in other places but be careful not to live in old data, an excellent way to start is with 0 and then increase the lifespan of this key result.

And there you go, you have learned a bit about how Suspense works and how you can use it today to deal with your promises.

React Queryalready supports Suspense, andRelayis our most outstanding example of Suspense API in practice.

If you got interested in what you saw here and want to see implemented versions of a library using the suspense API, you could check the next chapter of this article series, where is shown the New Suspense hooks for Meteor


Original Link: https://dev.to/grubba/making-promises-suspendable-452f

Share this article:    Share on Facebook
View Full Article

Dev To

An online community for sharing and discovering great ideas, having debates, and making friends

More About this Source Visit Dev To