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-debug-concurrent

v1.0.1

Published

A hook to debug React concurrent features. Attach callbacks to high and low priority renders.

Downloads

10

Readme

Use Debug Concurrent

A hook that helps you debug React concurrent features like useTransition a useDeferredValue by hooking into (no pun intended) concurrent rendering lifecycles, i.e. high priority and low priority render phases.

Debugging components that use concurrent rendering is tricky because they render (at least) twice, once due to the high priority update and another due to the low priority one and they may render even more times before comitting if low priority renders are interrupted.

This can make things very confusing when we want to inspect (e.g. log to console) values during render, especially because some values will differ between high and low priority renders.

With this hook, you can pass callbacks that will only run in a specific render phase, so you can easily inspect values and debug your components.

If you want to dive deeper into concurrent rendering or how this hook works, check this article.

You can check a live demo here: https://stackblitz.com/edit/react-wzwn93

Installation

npm install use-debug-concurrent

Types are already included.

Usage

import { useDebugConcurrent } from "use-debug-concurrent";

export default function App() {
  // This state will be updated by
  // HIGH priority updates
  const [filter, setFilter] = useState("");
  // This state will be updated by
  // LOW priority updates
  const [delayedFilter, setDelayedFilter] = useState("");
  const [isPending, startTransition] = useTransition();

  useDebugConcurrent({
    onFirstRenderStart: () => console.log("First render started"),
    onFirstRenderEnd: () => console.log("First render ended"),
    onHighPriorityStart: () => console.log("High priority render started"),
    onHighPriorityEnd: () => console.log("High priority render ended"),
    onLowPriorityStart: () => console.log("Low priority render started"),
    onLowPriorityEnd: () => console.log("Low priority render ended"),
  });

  return (
    <div>
      <input
        value={filter}
        onChange={(e) => {
          setFilter(e.target.value);
          startTransition(() => {
            // Here we're triggering the low
            // priority update that will
            // change `delayedFilter`'s value
            setDelayedFilter(e.target.value);
          });
        }}
      />

      <List filter={delayedFilter} />
    </div>
  );
}

const List = memo(({ filter }) => {
  const filteredList = list.filter((entry) =>
    entry.name.toLowerCase().includes(filter.toLowerCase()),
  );

  return (
    <ul>
      {filteredList.map((item) => (
        <li key={item.id}>
          {item.name} - ${item.price}
        </li>
      ))}
    </ul>
  );
});

Caveats

First renders are ambiguous in terms of priority

When the component renders for the first time, we cannot know whether that render is a high priority or low priority render just by looking at the component itself, we would need to understand what triggered the render in the first place, which comes from higher up in the component tree.

For instance, a component could be conditionally rendered by a parent component, and that parent component could be re-rendered by either a high priority or low priority update, which would make the child component's first render have the same priority as the parent's.

This is why we have two callbacks for first renders, onFirstRenderStart and onFirstRenderEnd.