Skip to content

Kornil/react-use-stateful-promise

Repository files navigation

UseStatefulPromise react hook

npm version build dependencies bundlephobia codecov license

A tiny, no-dependencies, fully type-safe React hook for running async functions with built-in status management, cancellation, reset, state synchronization and optional side effects.

Features

  • πŸš€ Run any async function (fetch or any other library or custom)
  • πŸ‘οΈ Track async operation status idle | loading | success | error
  • 🧠 Stores data & error inside hook state
  • ❌ Supports cancellation (prevents state updates after cancel)
  • πŸ”„ Supports reset (cancels and restores initial state)
  • πŸ”’ Race-condition safe (only the latest call can update state)
  • πŸͺΆ Lightweight (no dependencies)
  • πŸ”§ Fully typed with TypeScript generics
  • βš›οΈ React Compiler compatible (no need for useCallback)

Demo

Live Demo on GitHub Pages

The demo showcases:

  • Running successful async operations
  • Error handling on rejected async operations
  • Canceling in-flight promises
  • Resetting state
  • Ensuring no race conditions (Only the latest invocation resolves β€” stale promises are ignored automatically.)
  • Visualizing status transitions (IDLE β†’ LOADING β†’ SUCCESS / ERROR)

You can also explore the full demo source code inside the /demo folder of the repository.

Install

npm:

npm install react-use-stateful-promise

yarn:

yarn add react-use-stateful-promise

Usage

TypeScript (with types):

import { useStatefulPromise, Status } from "react-use-stateful-promise";

import { User } from "./types";

function Example() {
  const fetchUser = async (id: number) => {
    const res = await fetch(`/api/user/${id}`);
    return res.json();
  };

  const { status, data, error, run, cancel, reset } = useStatefulPromise<
    User,
    [number]
  >(fetchUser, {});

  return (
    <div>
      <button onClick={() => run(1)}>Load user</button>

      {status === Status.LOADING && <p>Loading...</p>}
      {status === Status.ERROR && <p>Error: {error?.message}</p>}
      {status === Status.SUCCESS && <pre>{JSON.stringify(data.name)}</pre>}

      <button onClick={cancel}>Cancel</button>
      <button onClick={reset}>Reset</button>
    </div>
  );
}

JavaScript (no types):

import { useStatefulPromise, Status } from "react-use-stateful-promise";

function Example() {
  const fetchUser = async (id) => {
    const res = await fetch(`/api/user/${id}`);
    return res.json();
  };

  const { status, data, error, run, cancel, reset } = useStatefulPromise(
    fetchUser,
    {}
  );

  return (
    <div>
      <button onClick={() => run(1)}>Load user</button>

      {status === Status.LOADING && <p>Loading...</p>}
      {status === Status.ERROR && <p>Error: {error?.message}</p>}
      {status === Status.SUCCESS && <pre>{JSON.stringify(data.name)}</pre>}

      <button onClick={cancel}>Cancel</button>
      <button onClick={reset}>Reset</button>
    </div>
  );
}

API Reference

const { status, data, run, cancel, reset } = useStatefulPromis(
  asyncFunction,
  initialData,
  {
    // optional callbacks for each action
    onSuccess: (newData) => newData,
    onError: (error) => error,
    onCancel: () => null,
    onReset: () => null,
  }
);

Returned values

Name Type Description
status Status ("IDLE" | "LOADING" | "ERROR" | "SUCCESS") The current state of the async call.
data T The resolved value from the async function.
error Error | null The caught error if the async function rejects.
run(...args) (...args: Args) => Promise<T> Runs the async function with the given arguments, updates state accordingly. Returns the underlying promise for chaining.
cancel() () => void Cancels the current pending async call and resets the hook to IDLE. Prevents updates from the canceled promise.
reset() () => void Fully resets state, clears data and error, and cancels any pending promise.

Parameters

Parameter Type Required Description
asyncFunction (…args: Args) => Promise<T> βœ”οΈ Yes Any function returning a Promise. The hook manages its lifecycle.
initialData T βœ”οΈ Yes Initial value for data.
options object βœ–οΈ No Optional callbacks triggered on success, error, cancel, or reset.
options.onSuccess (data: T) => void βœ–οΈ No Called when the async function resolves.
options.onError (error: Error) => void βœ–οΈ No Called when the async function rejects.
options.onCancel () => void βœ–οΈ No Called when the async operation is cancelled.
options.onReset () => void βœ–οΈ No Called when reset() is invoked.

Contributing

Contributions are welcome and appreciated, be it opening issues, opening pull requests or just asking questions.

The repository includes the demo environment for easier testing of the hook.

To start working, fork and clone the repository locally and then

cd react-use-stateful-promise

npm i # Install deps

npm run test # Run tests
npm run dev # Spin up demo environment

The hook code is located in the /lib folder.

The demo code is located in the /demo folder.

LICENSE

MIT

About

A React hook for managing async operations with status, data and cancellation.

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors 2

  •  
  •