# react-async's newest release is from 2020, its default branch is next, and its README explains upgrading to v9

> async-library/react-async is an ISC-licensed React component and hook for declarative promise resolution, with zero dependencies and four different consumption styles. What a careful adopter needs to know is that the published package stopped in March 2020 while the default branch is still being pushed, and that the compatibility testing is three npm scripts that rewrite the root manifest to install old React versions.

**async-library/react-async** — 🍾 Flexible promise-based React data loader

- Repository: https://github.com/async-library/react-async
- Website: https://docs.react-async.com/
- Stars: 2,140 · Forks: 86
- Language: JavaScript
- License: ISC
- Published: 2026-09-30 · Updated: 2026-09-30 · Language: en
- Canonical page: https://hysenlabs.com/projects/async-library-react-async

## The published package stopped in 2020 and the branch is still moving

Two dates define the state of this repository, and they are six years apart.

The release history shows v10.0.0 published on 2019-12-02, an alpha of the same version on the same day, and v10.0.1 on 2020-03-27 with a release note reading TypeScript fixes. Nothing has been published to the registry since. The last push to the repository is 2026-09-29, and the default branch is not `main`, it is `next`.

Read together those facts describe a project whose published surface is stable and old while its development branch is still active. That is not necessarily a problem, because a stable package that does not need to change is a good outcome for a small utility library. It does mean two things for anyone adopting it. The code you install from npm is the 2020 code, not the code in front of you. And the six years of commits on the branch are invisible unless you read the history or install from a checkout.

The licence is ISC, the author field names one maintainer, and the repository is not archived. There is no deprecation notice and no statement about maintenance intentions, so the honest position is that nobody has published an answer to the question.

## The readme explains upgrading to v9 while the tags are at v10

The readme contains a blockquote about upgrading, and it is one version behind the repository it lives in. It announces a minor breaking change in version 9 and links to an upgrading page on the documentation site.

So the documentation's migration guidance covers the move into 9, the tags sit at 10.0.1, and the newest thing published anywhere in the project is a patch on 10. Nothing in the readme tells you what changed between 9 and 10, other than the release note for 10.0.0 itself, which reads Native TypeScript.

That release note is the whole public record of the largest change in the library's recent history. The feature list does confirm the current state, since it says the library is written in TypeScript and ships type definitions, and the repository carries a TypeScript configuration and Babel configuration at the root, so a conversion to native types is consistent with what is there. But a reader upgrading from an 8.x line is pointed at 9's notes and has to find the 10 change themselves.

The documentation structure is otherwise thorough and is split into a getting started section, an API reference broken into interfaces, configuration options, state properties and helper components, and a guide section covering async components, separating view from logic, async actions, optimistic updates and server-side rendering. Those pages are where the version-specific detail lives.

## Four consumption styles over one behaviour

The design commitment in the description is that the library makes no assumptions about the shape of your data or the type of request, and the list of things it works with is correspondingly wide: fetch, Axios, other data fetching libraries, and GraphQL clients.

What it offers instead of assumptions is choice about how you consume it, and there are four ways. Render props put the state into your component's render function. Context-based helper components take the state out of the render path entirely. The `useAsync` and `useFetch` hooks are the modern entry points, one generic and one aimed at requests. On top of those there is experimental Suspense support, flagged as experimental in the feature list rather than presented as stable.

Four APIs over one state machine is a real cost, and it is the cost of a library that has existed long enough to have grown a new style without deleting the old one. The documentation's guide section on separating view from logic is effectively the argument for choosing one, and the presence of a page dedicated to that question suggests the choice confuses people.

The state itself is described in the feature list rather than invented per component: an `isPending` flag, a `startedAt` timestamp and a `finishedAt` timestamp, with a whole API page devoted to state properties.

## Cancellation, re-runs and optimistic updates are props

The interesting design decision in this library is that the entire async lifecycle is expressed as configuration rather than as a separate data layer. Everything in the feature list is a prop or a callback.

There are two actions, `cancel` and `reload`, so the caller can abandon a request or start it again. There are three callbacks, `onResolve`, `onReject` and `onCancel`, so the three terminal outcomes of a promise are all handled. There are two props for automatic re-running, `watch` and `watchFn`, so a request can be repeated when a value changes. And there is an AbortController path for abortable fetch, which is linked to the browser feature of the same name rather than reimplemented.

Optimistic updates come through a single setter, `setData`, so you can write the expected result into the state before the promise settles. Server-side rendering comes through an initial value prop, which is what lets a component render with data already present rather than waiting on the client.

None of this is unusual, and that is the point. A user of this library does not learn a request cache, a key scheme or a normalisation format, because there is none. The trade is that you write the caching, the deduplication and the race-condition handling yourself.

## Compatibility is three npm scripts that rewrite the root manifest

The most interesting thing in the manifest is a set of scripts that install React itself in order to test against it.

There are three. One adds an old React as a root dev dependency and runs the component tests. One adds the canary release and runs the full suite. One adds the latest release and runs the full suite. And a fourth chains all three in sequence, so the compatibility check is the same three runs in a row.

What makes them worth reading is the shared helper they depend on. A script named for fixing React resolutions takes the root manifest, runs a `jq` expression that rewrites the resolution entries for both React packages to match whatever version is currently in the dev dependencies, writes the result to a temporary file, moves it over the original and reinstalls. So the test matrix mutates your package manifest as a side effect of running a test command, and it needs `jq` on the path to do it.

The old version it pins against is from late 2018, which places the lower bound of the supported range. The canary script places the upper one at the bleeding edge rather than at a stable release. Between them, the range this project tested itself against in 2020 is far wider than what most React libraries attempt, and it is a range nobody re-tested in the six years since.

## A Chromatic token is committed in a script

Two entries in the manifest are worth flagging on their own.

The first is the visual regression script, which invokes Chromatic with a workspace token written into the command line, along with a build target and a flag that makes changes non-failing. That token is in version control, in a file everyone who clones the repository can read. Whether it still points at a live workspace is not something the repository answers, but a token that was valid once should be treated as valid until its owner says otherwise, and rotating it is a small task.

The second is the browser support target, which is a single line and narrower than anything else in the project. The browserslist field contains only the last two Firefox versions. Not a range of versions, not a percentage of traffic, and no other browser at all.

For a published library that field decides how far the build transpiles, so the practical effect is that the output targets a browser that has supported everything the library uses for years, and does not commit to transpiling for anything else. If your application needs a wider build target, this is the setting to override before you rely on the bundled output, and it is also the setting that tells you how old this build configuration is.

## A lerna monorepo with codemods and eleven examples

The repository is a workspaces monorepo, with the root manifest declaring two globs, `examples/*` and `packages/*`, and a Lerna configuration beside it. The build and test scripts are all scoped through Lerna, which means the library and its examples are versioned and built separately even though they live in one tree.

The `codemods/` directory is the detail that rewards a second look. Codemods exist to rewrite code across a user's project during a major version migration, which is exactly the kind of thing a library needs when its release history spans many majors and its readme documents only the last one. A project that ships codemods has usually decided that hand-written migration notes are not enough, which again points at the v9 and v10 documentation gap rather than away from it.

The examples directory holds eleven runnable cases, and their names are a compact map of the library's surface: a basic fetch example, a basic hook example, a custom instance, a larger movie application, one using an AbortController, one with GraphQL, one with Next.js, one with React Native, one with React Router, one with Suspense and one with TypeScript. Each is its own workspace package with its own lint configuration and its own test command, run in CI with a flag that passes when no tests are found.

Supporting files follow the same pattern of a project with a real release process: separate files for Babel, Jest with its setup, ESLint and Prettier, a Renovate configuration for dependency updates, a Storybook configuration with its own Chromatic builds, a GitBook configuration for the documentation, a Codesandbox directory, a Vercel configuration for the examples site, and a brand directory.

## Conclusion

Use react-async if you want promise-shaped data loading without adopting a data layer, because its value is that it makes no assumption about the shape of your data or the kind of request you make, and it carries no dependencies at all. Three things to check before you install. Which artefact you are getting, since the newest tag on the registry is from March 2020 while the default branch is named next and has been pushed to within days, so the published package and the repository head are six years apart. Which consumption style you want, because render props, context helper components, two hooks and experimental Suspense support are four different APIs over the same behaviour. And which React version you are on, since the project's own compatibility scripts test against a version from 2018, against the canary channel and against latest, which tells you the range they cared about is wide and that you are outside it if you run something newer. The library is small, well documented and stable, which is exactly why the age of the release matters.

## FAQ

### What is the react-async library used for?

It is a React component and hook for declarative promise resolution and data fetching, which handles every state of the asynchronous process without assumptions about the shape of your data or the type of request. It works with fetch, Axios, other data fetching libraries and GraphQL clients, and it has zero dependencies.

### Does react-async support cancellation and optimistic updates?

Yes. There are `cancel` and `reload` actions, an `onCancel` callback alongside `onResolve` and `onReject`, and support for abortable fetch through an AbortController. Optimistic updates go through a `setData` setter, and automatic re-running is available through the `watch` and `watchFn` props.

### How do I install react-async?

The project documents installation on its documentation site rather than in the readme, and the package is published to the npm registry under `react-async`. The newest published version is 10.0.1, and the repository's default branch is `next` rather than `main`, so installing from a checkout gives you different code from the registry.

### Does react-async support server-side rendering?

Yes, through an initial value prop that lets a component render with data already available instead of waiting on the client. There is a dedicated server-side rendering page in the documentation guide, alongside pages on async components, async actions, optimistic updates and separating view from logic.

### Can I use react-async with hooks or Suspense?

Both are offered. You can choose between render props, context-based helper components, and the `useAsync` and `useFetch` hooks, and Suspense support is available but described as experimental. There is a runnable example for the hook form and another for Suspense in the repository's examples directory.

## Sources

- [async-library/react-async on GitHub](https://github.com/async-library/react-async)
- [License: ISC](https://github.com/async-library/react-async/blob/next/LICENSE)
- [Project website](https://docs.react-async.com/)
- [README](https://github.com/async-library/react-async/blob/next/README.md)
- [Releases](https://github.com/async-library/react-async/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/async-library-react-async
