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 🙏

© 2025 – Pkg Stats / Ryan Hefner

with-react

v1.0.0

Published

Composable component versions of React hooks

Readme

with-react

GitHub Repo stars npm GitHub npm npm GitHub top language

A collection of React components that wrap React hooks to provide a more composable API. Each component accepts a render prop that receives the hook's return value.

This enables a lot of features that previously violate the Rules of Hooks

Conditional Hooks

function UserProfile({ user, showDetails }) {
  return (
    <div>
      <h1>{user.name}</h1>

			<p> This is a really long description and there could be more markup or other components between here and the top of the component. Since hooks need to be declared at the top of the component function, instead of in the JSX, you may want to use WithState instead of useState just for colocation reasons.
		  </p>

      {showDetails && (
        <WithState initialState={user.lastLogin}>
          {(lastLogin, setLastLogin) => (
            <div>
              Last login: {lastLogin}
              <button onClick={() => setLastLogin(new Date())}>
                Update
              </button>
            </div>
          )}
        </WithState>
      )}
    </div>
  )
}

Hooks within loops

This is a special case of conditional hooks, but sometimes you're rendering a lot of items in a loop and it's not worth creating a custom component for them because they require too much data from the parent scope.

But then when you need to add some state to each one, React forces you to wrap it in a component. By using WithState, that component is provided for you and you can keep your list items owned by the parent.

const items = ['apple', 'banana', 'orange']

function FruitList() {
  return (
    <ul>
      {items.map((item) => (
        <WithState key={item} initialState={0}>
          {(count, setCount) => (
            <li>
              {item}: {count}
              <button onClick={() => setCount(count + 1)}>+</button>
            </li>
          )}
        </WithState>
      ))}
    </ul>
  )
}

Form Status

The useFormStatus() hook from react-dom treats any parent <form> like a context provider, and for that reason must be used in a child component of the form.

Avoid creating a component boundary by using WithFormStatus and getting the value inline.

function SearchForm() {
  return (
    <form action="/search">
      <input name="q" />
      <WithFormStatus>
        {(status) => (
          <button disabled={status.pending}>
            {status.pending ? 'Submitting...' : 'Submit'}
          </button>
        )}
      </WithFormStatus>
    </form>
  )
}

Promise Resolution

The use() hook can unwrap promises, but it must be used in a child of the suspense boundary it's meant to trigger. Since data is best fetched at the route level, these promises will almost always be naturally higher than the UI wheir their suspense boundary needs to be.

The WithUse component allows you to pass a promise and get its resolved value directly within it.

This use-case resembles React Router's Await component, which is a better name but I had to stick with the theme here.

function UserDetails() {
  return (
    <div>
      <h1>User Details</h1>
			<Suspense fallback={<Spinner />}>
				<WithUse value={getUserPromise}>
					{(user) => (
						<div>
							<p>Name: {user.name}</p>
							<p>Email: {user.email}</p>
						</div>
					)}
				</WithUse>
			</Suspense>
    </div>
  )
}

Available Components

WithState and WithFormStatus are the most useful | Hook | Component | |------|-----------| | useActionState | WithActionState | | useCallback | WithCallback | | useContext | X | | useDeferredValue | WithDeferredValue | | useEffect | X | | useFormStatus | WithFormStatus | | useId | WithId | | useImperativeHandle | X | | useInsertionEffect | X | | useLayoutEffect | X | | useMemo | WithMemo | | useReducer | WithReducer | | useRef | X | | useState | WithState | | useSyncExternalStore | WithSyncExternalStore | | useTransition | WithTransition | | use | WithUse |