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

@savchenko91/rc-route-constant

v4.0.5

Published

Routes for React

Readme

What is it

Do you have a file src/constants/routes.js? Good. This libary will help you with it. See example:

const ROUTES = {
  LOGIN: new Route({ name: "Login page", path: "/login" }),
  MAIN: new Route({
    name: "Main page",
    path: "/",
    redirect: "/main",
    payload: { ICON: SomeIcon },
  }),
};

console.log(ROUTES);
// {
//   LOGIN: {
//     NAME: 'Login page',
//     PATH: '/login',
//     REDIRECT: '/login',
//     REDIRECT_PATH: '/login',
//     isCurrent: false,
//     isPrevious: false,
//     isPartOf: (string) => boolean,
//   },
//   MAIN: {
//     NAME: 'Main page',
//     PATH: '/',
//     REDIRECT: '/main',
//     REDIRECT_PATH: '/main',
//     PAYLOAD: {
//       ICON: React.component
//     }
//     ...
//   }
// }

Solves Problems

  • You do not need to store queries in redux when user left page and redirect to URL with stored queries when user comes back!
  • Is this route current?
  • Is this route previous? (WARNING! Need some actions to make it works!)
  • Page titles in one place!
  • Is this route part of that route?
  • Get routes for Breadcrumbs
  • Get routes by regExp

Main usage

Route constants

export enum Params {
  catId = 'catId',
  userId = 'userId',
}

export enum Paths {
  cats = 'cats',
  create = 'create',
  remove = 'remove',
  users = 'users',
}

export type CAT = `/${Paths.users}/:${Params.userId}/${Paths.cats}/:${Params.catId}`
export type CAT_CREATE = `/${Paths.users}/:${Params.userId}/${Paths.cats}/create`;
export type CAT_LIST = `/${Paths.users}/:${Params.userId}/${Paths.cats}`
export type CAT_REMOVE = `/${Paths.users}/:${Params.userId}/${Paths.cats}/:${Params.catId}/remove`;
export type USER = `/${Paths.users}/:${Params.userId}`;
export type USER_LIST = `/${Paths.users}`;

const ROUTES = {
  CAT: new Route<CAT>({
    name: 'User\'s cat',
    path: '/user/:userId/cats/:catId'
  }),
  CAT_CREATE: new Route<CAT_CREATE>({
    name: 'Create cat',
    path: '/users/:userId/cats/:catId'
  }),
  CAT_LIST: new Route<CAT_LIST>({
    name: 'Cats',
    path: '/users/:userId/cats/:catId'
  }),
  CAT_REMOVE: new Route<CAT_REMOVE>({
    name: 'Remove cat',
    path: '/users/:userId/cats/:catId/remove'
  }),
  USER: new Route<USER>({
    name: 'User',
    path: '/users/:userId'
  }),
  USER_LIST: new Route<USER_LIST>({
    name: 'Users',
    path: '/users'
  })
}

// Well done! Now you can use it!
<Route path={ROUTES.USER.PATH}>

// Need a link href?
<Link to={ROUTES.CAT.PATH.replace(Params.userId, '33').replace(Params.catId, '77')}>

Set previous

Use function setPreviousRoute to set property isPrevious

import { useLocation } from "react-router-dom";
import { setPreviousRoute } from "@savchenko91/rc-route-constant";
import ROUTES from "./path/to/your/constants/routes";

function ParentComponent() {
  const location = useLocation();

  // Write "{ ...ROUTES }" if you use TS because of ERROR TS2345
  setPreviousRoute({ ...ROUTES });

  return <div>...</div>;
}

Additional features

getCurrent

You can automatically set a page title

import { useLocation } from "react-router-dom";
import { getCurrent } from "@savchenko91/rc-route-constant";
import ROUTES from "./path/to/your/constants/routes";

function Component() {
  useLocation(); // render on every pathname change

  // If uou use an old TS version you need to write "{ ...ROUTES }"
  document.title = `You are on page "${getCurrent({ ...ROUTES }).NAME}`;

  return <div>...</div>;
}

getListByRegExp

import { getListByRegExp } from "@savchenko91/rc-route-constant";
import ROUTES from "./path/to/your/constants/routes";

function ListWithAppLinks() {
  const routes = useMemo(
    () => getListByRegExp(ROUTES, /\/app\/([a-z-]+)$/),
    []
  );

  return (
    <ul>
      {routes.map((route) => (
        <li>
          <a className={route.LABEL} href={route.REDIRECT_PATH}>
            {route.PAYLOAD.ICON}
            {route.NAME}
          </a>
        </li>
      ))}
    </ul>
  );
}

getListForEveryLocation

import { useLocation } from "react-router-dom";
import { getListForEveryLocation } from "@savchenko91/rc-route-constant";
import ROUTES from "./path/to/your/constants/routes";

function Breadcrumbs() {
  const location = useLocation();

  const routes = useMemo(
    () => getListForEveryLocation(ROUTES, location.pathname),
    []
  );

  return (
    <ul>
      {routes.map((route, i) => (
        <li>
          <a href={route.REDIRECT_PATH}>/ {route.NAME}</a>
        </li>
      ))}
    </ul>
  );
}

Store queries

This is the case:

  1. You have two tabs by routes search/cats and search/users on page search
  2. You want to store search queries when user leaves the page search
  3. You want to store last opened tab when user leaves the page search

Store them into REDIRECT property!

React.useEffect(
  () => () => {
    if (ROUTES.CAR.isCurrent) {
      // Store current pathname into CLIENT.REDIRECT
      ROUTES.CLIENT.REDIRECT = location.pathname;
      // Store current tab into SEARCH.REDIRECT
      ROUTES.SEARCH.REDIRECT = ROUTES.CAR;
    } else {
      // Store current pathname into CLIENT.REDIRECT
      ROUTES.CAR.REDIRECT = location.pathname;
      // Store current tab into SEARCH.REDIRECT
      ROUTES.SEARCH.REDIRECT = ROUTES.CLIENT;
    }
  },
  []
);

Okey. We store them all and now we want to get them back:

const searchPath = ROUTES.SEARCH.REDIRECT_PATH
console.log(searchPath) // /search/cats?user=John&breed=Siamese
<Link to={searchPath}>Search page</Link>

See? You store the pathnames into ROUTES.CAT and ROUTES.USER but you get them from ROUTES.SEARCH If you want to know how it works see the code below:

// CODE FROM THIS LIBRARY!
get REDIRECT_PATH(): string {
  if (!this.REDIRECT) return this.PATH;

  return this.REDIRECT instanceof Route ? this.REDIRECT.REDIRECT_PATH : this.REDIRECT;
}

Extend it!

Sometimes you have many params in a path and you need to add some queries so you might want to extend Routes

import RcRoute from '@savchenko91/rc-route-constant';
import qs from 'qs';

export class Route<P extends string, RouteParams extends Record<string, string | undefined> = {}> extends RcRoute<P> {
  buildHref = (obj: RouteParams, queries?: Record<string, string>) => {
    const hrefWithReplacedParams = Object.entries(obj).reduce<string>((path, [key, value = '']) => {
      return path.replace(`/:${key}?`, `/${value}`).replace(`/:${key}`, `/${value}`);
    }, this.PATH);
    // Remove optional params if they exist
    const href = hrefWithReplacedParams.replace(/\/:([a-zA-Z-_])+\?/g, '');

    if (!queries) return href

    return `${href}${qs.stringify(queries, { skipNulls: true, addQueryPrefix: true })}`;
  };
}

// Well done! Now you can use it!
<Link to={ROUTES.CAT.buildHref({ userId: '33', catId: '77' }, { cute: 'true' })}>