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-promised

v1.3.0

Published

A React hook to implement asynchronous callbacks without having to deal with asynchronicity.

Downloads

1,403

Readme

use-promised

Stable release

A React hook to implement asynchronous callbacks without having to deal with asynchronicity.

The problem

Can you tell what could go wrong with this code?

function FeedbackForm() {
  const [result, setResult] = useState();
  const [error, setError] = useState();

  function onSubmit() {
    API.submitFeedback()
      .then((receivedResult) => {
        setResult(receivedResult);
      })
      .catch((receivedError) => {
        setError(receivedError);
      });
  }

  return (
    <>
      <button onClick={onSubmit} type="button">
        Submit feedback
      </button>
      <p>Result: {result}</p>
      <p>Error: {error}</p>
      ...
    </>
  );
}

Here are some issues with this code:

  1. The button can be submitted multiple times while the operation is pending. The fix is adding more state to track the loading state.
  2. When the button is clicked multiple times, there's a race condition which result will be shown eventually.
  3. When the component unmounts in the middle of the request, you'll see the dreaded "Can't perform a React state update on an unmounted component" warning.
  4. If an error is received, it won't be removed when a new attempt is made – even if a subsequent request succeeds.

The list goes on but the point is: Handling async callbacks in React components is hard.

Maybe you've heard that you can avoid these issues by moving your code into useEffect, but that hook has its own peculiarities to be aware of.

This solution

This is a custom hook that attempts to remove all the complexity that comes with handling asynchronicity in callbacks correctly.

Features:

  • Feels like synchronous programming – no useEffect.
  • Pending requests are canceled when they are interrupted by another request.
  • Impossible states like having a result and error simultaneously are prevented.
  • When you're using TypeScript you'll benefit from additional guardrails.
  • If your asynchronous callback reaches through multiple levels of components, you can subscribe to the promise result right on the level where you need it – no need to pass down a loading and error state. If desired, you can subscribe in multiple components at the same time.

Example

import usePromised, {PromiseState} from 'use-promised';

function FeedbackForm() {
  const [promise, setPromise] = usePromised();

  function onSubmit() {
    setPromise(API.submitFeedback());
  }

  return (
    <>
      <button
        disabled={promise.pending}
        onClick={onSubmit}
        type="button"
      >
        Submit feedback
      </button>
      {promise.fulfilled && (
        <p>Result: {promise.result}</p>
      )}
      {promise.rejected && (
        <p>Error: {promise.error}</p>
      )}
    </>
  );
}

Note that you can also read the state in a generic fashion from promise.state.