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

react-use-latest-state

v1.0.6

Published

A lightweight React package that enhances the reliability of state values within functional components. By utilizing useRef under the hood, useLatestState ensures that you always access the latest state value, eliminating common pitfalls when working with

Downloads

16

Readme

useLatestState

npm

Overview

useLatestState is a lightweight React package that enhances the reliability of state values within functional components. It addresses the common issue where accessing state values inside functions might yield outdated results. By leveraging useRef under the hood, this package ensures that you always get the latest state value.

Motivation

In React, working with state values inside functions can sometimes lead to unexpected behavior due to closures capturing stale state. useLatestState aims to provide a straightforward solution to this issue, making it easier for developers to maintain the accuracy of their state values.

Consider the following code snippet:

function App() {
  const factsDivRef = useRef(null);
  const [facts, setFacts] = useState([]);

  // Simple logic to auto-scroll to bottom
  // everytime a new fact is loaded
  useEffect(() => {
    factsDivRef.current.scrollTop = factsDivRef.current.scrollHeight;
  }, [facts]);

  function fetchAFact() {
    setTimeout(() => {
      fetch("https://catfact.ninja/fact").then(async (response) => {
        // `facts` in the closure
        // does not hold the latest
        // value
        console.log(facts);

        const data = await response.json();

        // Does not work well for
        // concurrent requests
        setFacts([
          ...facts,
          {
            id: Date.now(),
            fact: data.fact
          }
        ]);
      });
    }, 250); // Waits 250 ms before triggering the request, simulates a long request
  }

  return (
    <div className="card">
      <span className="title">Facts</span>
      <div ref={factsDivRef} className="facts">
        {facts.map((fact) => (
          <div key={fact.id} className="fact">
            <span>{fact.fact}</span>
          </div>
        ))}
      </div>

      {/* Clicking rapidly causes concurrent requests and does not work as expected */}
      <button onClick={fetchAFact}>Fetch a fact!</button>
    </div>
  );
}

In the above app, Cat facts are fetched and displayed. However, when the button is clicked rapidly, triggering concurrent requests simultaneously, the app's behavior becomes unexpected. The fact fetched by the first response is added to the facts; however, the value is only updated when other concurrent requests are resolved one by one.

This inconsistency arises because the value of facts inside the closure does not hold the latest value when the concurrent requests are processed. Such logical problems are challenging to anticipate during coding but become apparent in hindsight.

To address this issue, the useLatestState hook from react-use-latest-state is employed (see the fixed code):

import { useLatestState } from "react-use-latest-state";

...

function App() {
  const factsDivRef = useRef(null);

  // Use `useLatestState` hook
  const [facts, setFacts] = useLatestState([]);

  // Simple logic to auto-scroll to bottom
  // everytime a new fact is loaded
  useEffect(() => {
    factsDivRef.current.scrollTop = factsDivRef.current.scrollHeight;
  }, [facts]);

  function fetchAFact() {
    setTimeout(() => {
      fetch("https://catfact.ninja/fact").then(async (response) => {
        // `facts` in the closure
        // now holds the latest value
        console.log(facts());

        const data = await response.json();

        // Works well for
        // concurrent requests
        setFacts([
          ...facts(),
          {
            id: Date.now(),
            fact: data.fact
          }
        ]);
      });
    }, 250);
  }

  return (
    <div className="card">
      <span className="title">Facts</span>
      <div ref={factsDivRef} className="facts">
        {facts().map((fact) => (
          <div key={fact.id} className="fact">
            <span>{fact.fact}</span>
          </div>
        ))}
      </div>

      <button onClick={fetchAFact}>Fetch a fact!</button>
    </div>
  );
}

In the fixed example, this issue is addressed by resolving the core problem. Now, clicking the button rapidly does not repeat the same unexpected behaviour.

Installation

npm install react-use-latest-state

Usage

import { useLatestState } from "react-use-latest-state";

const YourComponent = () => {
  const [state, setState] = useLatestState(initialValue);

  // Use state as a function to get the latest value
  const handleClick = () => {
    console.log(state());
  };

  return (
    // Your component JSX
  );
};

CONTRIBUTIONS

Please refer to CONTRIBUTING.md for more information.

CODE OF CONDUCT

Please refer to CODE_OF_CONDUCT.md for more information.