npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

use-await-data

v1.0.5

Published

A React hook that executes an async task to populate the desired data.

Downloads

24

Readme

React Hook: useAwaitData

NPM npm semantic-release microbundle

useAwaitData is a React hook that executes an async task to populate the desired data.

Features

  • Invalidate stale executions
  • Abort executions by a callback
  • Minimum re-renders
  • Zero-dependency
  • React >= 17 support
  • TypeScript support
  • ESM/CJS/UMD support

Example

import useAwaitData from "use-await-data"

const ShowData = ({ query }: { query: Query }) => {
  const result = useAwaitData(
    async ({ tick, signal }) => {
      const a = await someTask(query)
      tick = await tick()
      const b = await anotherTask(a)
      tick = await tick()
      return await lastTask(b)
    },
    [query, someTask, anotherTask, lastTask],
  )
  switch (result.status) {
    case "fulfilled":
      return <Show value={result.value} />
    case "rejected":
      return <ShowError message={result.error.message} />
    case "running":
      return <ShowLoading onAbort={result.abort} />
    case "aborted":
      return <ShowAborted />
    // That's all!
  }
}

TL;DR

What's the Usage?

You can handle aborts of stale runs by doing:

  • Insert tick = await tick() between every statement in your async function
  • You can also use signal with AbortController-compatible APIs such as fetch

Other usage is fully illustrated in the above example. You may also want to see Illustrations of operating timelines section below.

When to Use This Package

When you just want the data which requires some async tasks (e.g. search), that's what this package is for.

If you just want to perform async operation (e.g. visual effects), this package can do it but other similar packages would also work.

Why?

You may notice there're already similar packages in the wild, such as use-async-effect, @react-hook/async, etc. This package basically does the same thing as them, but our primary motivation is to handle re-runs of the async function efficiently.

This package has of course a functionality to abort manually, and also a functionality to automatically “invalidate” the previous run of the async function when the dependencies have been updated and the stale task is not settled yet. This will reduce unexpected state changes and thus re-renders of the component.

The returned object of useAwaitData always stands for the current run of the async function. Even if the invalidated run has settled while the current run is ongoing, the result of the invalidated run will be ignored and no re-render occur.

Detailed Behavior and Usage

Every update of the dependencies causes a re-run of the task! This hook automatically invalidates the execution of the stale task. When a invalidate occurs, the old task will be treated as if it was aborted (abort process is described in the further paragraphs), but the resulting status remains as "running" until the new task run settles. Please pay attention to your dependencies — you should avoid unnecessary updates as much as possible in order to prevent the task from wasted runs. For this reason, unlike React's useEffect hook, the task function is run at only the first time even if dependencies parameter was not provided.

When the status property of the result object is "running", you can access to the abort property which is a () => void to request abort to the scheduler. Note that abort only works while the status is "running", otherwise it's just a no-op.

The first parameter of task function will be a Scheduler object, whose shape is { tick: Tick; signal: AbortSignal } and Tick is () => PromiseLike<Tick>. You may want to call the tick function with some idiomatic syntax like tick = await tick() periodically in the task function, in order to handle aborting of the task — tick immediately rejects once abort has been requested elsewhere, otherwise it immediately resolves and allows you to continue further operations. You can also use the signal which comes from an AbortController for supported APIs such as fetch.

Even if you don't use the tick function, once abort request has been filed, this hook results in "abort" status immediately, and it won't change until the next update of the dependencies, regardless of whether the task will have successfully fulfilled or rejected. But if it's already in a settled status such as "fulfilled" or "rejected", abort function doesn't affect the status.

Illustrations of operating timelines

Asterisks (*) at the bottom of each graph indicate re-renders caused by useAwaitData. Note that these don't directly mean updates of the result object. Updates are indicated as vertical bars on the “status” lines.

Case #1 — Dependencies update before the first run settles

time:    |-------------------------------------------------------------------------->
event:   |<-initial call |<-deps update
run #0:  |===============|<-(invalidated)===>|<-reject at tick·····>|<-(est. settle)
run #1:                  |==============================>|<-resolve
status:  |<-running----->|<-running--------------------->|<-fulfilled--------------->
                                                         *

Case #2 — Dependencies update after the first run settled

time:    |-------------------------------------------------------------------------->
event:   |<-initial call                  |<--deps update
run #0:  |================>|<-reject
run #1:                                   |===============>|<-resolve
status:  |<-running------->|<-rejected--->|<-running------>|<-fullfilled------------>
                           *                               *

Case #3 — Dependencies update after the first run aborted but tick isn't used

time:    |-------------------------------------------------------------------------->
event:   |<-initial call  |<-abort      |<-deps update             |<-abort (ignored)
run #0:  |================|<-(abort requested but no tick)====>|<-resolve (ignored)
run #1:                                 |============>|<-resolve
status:  |<-running------>|<-aborted--->|<-running--->|<-fulfilled------------------>
                          *                           *