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

react-nav-handler

v0.2.0

Published

Decouple navigation requests from url changes

Downloads

3

Readme

React nav handler

Decouple navigation requests from url changes.

Rationale

Components may sometimes request to change the url. For example, a HelpButton component may want to navigate to the help screen when pressed. If you want to reuse such a component in different contexts, then the required url change may depend on the context. For example, in the context of the "editor" page the help button should navigate to "/editor/help", but in the context of the "dashboard" page the button should navigate to "/dashboard/help".

This problem can be solved by informing the HelpButton about its context, or by explicitly passing a url into the HelpButton. Although this simple solution is usually all you need, there are cases where it leads to a lot of prop drilling, especially when components are reused in different locations. In those cases, the code will be simpler and cleaner if components can just call navToHelp and remain agnostic of the exact url change that is required.

We can achieve this by adding so-called navigation pages to the url-router. When a navigation page is mounted, it registers itself and its associated url in the navigation handler. In the example code below, the EditorNavPage is associated with /editor and the DashboardNavPage is associated with /dashboard. When a component calls navToHelp then this request is passed (under the hood) to the navigation handler, who will call the navToHelp function of the navigation page that matches the current url. This means that depending on the current url, the HelpButton will navigate to /dashboard/help or to /editor/help.

Synopsis

// navEvents.ts
export const navToHelp = (): void => {
  navHandler.getNavFn('navToHelp', navToHelp)();
}

// DashboardNavPage.tsx
import { useInstallNavPage } from 'react-nav-handler';
import { navToHelp } from 'navEvents';

export const DashboardNavPage = (props: { children }) => {
  useInstallNavPage(
    'DashboardNavPage',
    {
      navToHelp: (() => {
        history.push('/dashboard/help');
      }) as typeof navToHelp,
    }
  );
  return <>{props.children}</>;
};

// EditorNavPage.tsx
import { useInstallNavPage } from 'react-nav-handler';
import { navToHelp } from 'navEvents';

export const EditorNavPage = (props: { children }) => {
  useInstallNavPage(
    'EditorNavPage',
    {
      navToHelp: (() => {
        history.push('/editor/help');
      }) as typeof navToHelp,
    }
  );
  return <>{props.children}</>;
};

// UrlRouter.tsx
import { DashboardNavPage } from 'DashboardNavPage';
import { EditorNavPage } from 'EditorNavPage';

export const UrlRouter = () => {
  return (
    <>
      <DashboardNavPage>
        <Route path="/dashboard">
          <HelpButton />
        </Route>
      </DashboardNavPage>
      <EditorNavPage>
        <Route path="/editor">
          <HelpButton />
        </Route>
      </EditorNavPage>
    </>
  )
}

// HelpButton.tsx
import { navToHelp } from 'navEvents';

export const HelpButton = () => {
  return (
    <button onClick={() => navToHelp()}>Help</button>;
  )
}

More fine-grained control

The proposed approach to navigation is unusual, because navigation happens based on the current url, but not on the caller. Specifically, if the caller is a React component, then it doesn't matter in which part of the rendering tree that component is located. This can be too coarse grained though. For example, imagine that we're on the url /editor and we're showing an Editor component that has a HelpButton. Following the previous example, when we press this button, we will navigate to /editor/help. However, the page may also have a HelpButton in the application frame that should always navigate to /help. To support such cases, you can add a requesterId in the call to navToHelp.

// navEvents.ts
export const navToHelp = (requesterId: string): void => {
  navHandler.getNavFn('navToHelp', navToHelp)(requesterId);
};

// EditorNavPage.tsx
export const EditorNavPage = (props: { children }) => {
  useInstallNavPage('EditorNavPage', {
    navToHelp: ((requesterId: string) => {
      if (requesterId !== 'Editor') return false;
      history.push('/editor/help');
    }) as typeof navToHelp,
  });
  return <>{props.children}</>;
};

What this communicates is that EditorNavPage will handle navToHelp requests from "Editor", but not from other requesters. When a navivation function returns false then navHandler will continue by passing the navigation request to the next navigation page. Of course, you must ensure that one of the mounted navigation pages processes the requests, or an error will be thrown.