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

@calvear/react-spa-routerizer

v1.0.11

Published

React library for application routing (based on React Router) that prevents boilerplate code.

Downloads

23

Readme

React SPA Routerizer

React library for application routing (based on React Router) that prevents boilerplate code. This library eases routes definitions and routing job. Exposes a generic Router for create base app router, some hooks and a routes service (for breadcrumbs for example).

Structure 📋

├── README.md
├── LICENCE.md
├── CHANGELOG.md
├── .vscode/ # vscode shared development config
├── src/
│   ├── router/
│   │   ├── components/
│   │   │   ├── RouteChild.jsx # handle page rendering
│   │   │   ├── Router.jsx # handle Switch and Route definitions
│   │   │   └── RouterProvider.jsx # initializes router.service
│   │   ├── router.hook.js # library hooks
│   │   └── router.service.js # handle current routes
│   └── index.js
├── package.json
├── jsconfig.js
├── .babelrc
├── .eslintrc.json
└── .prettierrc.json
  • Router.jsx: contains generic router logic.
  • RouteChild.jsx: render current route component (a.k.a. page) and updates document (browser tab) title.
  • route.hook.js: contains hooks like useRoutePayload for get specific route payload.
  • route.service.js: routes handler. Initializes routing. Calculates complete paths for nested routes and data for breadcrumbs.
  • index.js: exports router, hooks and routes handler/service.

How To Use 💡

Should be initialized with RouterProvider on App.jsx like:

import { RouterProvider, Router } from '@calvear/react-spa-routerizer';
import routes from 'routes'; // your routes definition JSON

export default function App()
{
    return (
        <RouterProvider routes={ routes }>
            <Router
                loader={ <div>Loading</div> }
                DefaultChild={ () => <div>Page Not Found</div> }
            />
        </RouterProvider>
    );
}

Routes format are shown below:

{
    key: 'unique-id',
    title: 'Main Page',
    path: '/',
    Layout: LayoutComponent,
    Child: PageComponent,
    payload: {
        ...
    }
}
  • key: any unique string for route.
  • title: title shown in tab browser.
  • path: relative path of route.
  • Layout: optional. Layout component.
  • Child: Route/Page component.
  • payload: optional. The payload defined for route. May be accessed with useRoutePayload hook.

Routers format are shown below:

{
    key: 'unique-id',
    path: '/',
    Layout: LayoutComponent,
    DefaultChild: NotFoundPage,
    payload: {
        ...
    },
    routes: [
        ...
    ]
}
  • key: any unique string for router.
  • title: optional. Title for nested routes, shown in tab browser.
  • path: base path for nested routes.
  • Layout: optional. Layout component for every child.
  • DefaultChild: default component on no one defined route.
  • payload: optional. The payload defined for router. May be accessed with useRoutePayload hook. Will be merged with low priority with child payload.
  • routes: array of sub-routes.

Example:

import { lazy } from 'react';

// layouts container.
const Layouts = {
    Card: lazy(() => import('layouts/card'))
};

// pages container.
const Pages = {
    Main: lazy(() => import('pages/main')),
    Detail: lazy(() => import('pages/detail')),
    UserProfile: lazy(() => import('pages/user-profile')),
    UserEdit: lazy(() => import('pages/user-edit'))
};

export default [
    {
        key: 'main-page',
        title: 'Main Page',
        path: '/',
        Layout: Layouts.Card,
        Child: Pages.Main,
        payload: {
            header: 'List of Items'
        }
    },
    {
        key: 'detail-page',
        title: 'Detail Page',
        path: '/detail/:name',
        Layout: Layouts.Card,
        Child: Pages.Detail
    },
    {
        key: 'user-router',
        path: '/user',
        Layout: Layouts.Card,
        DefaultChild: () => <div>Page Not Found</div>,
        payload: {
            header: 'User Page'
        },
        routes: [
            {
                key: 'user-profile',
                title: 'User Profile',
                path: '/profile',
                Child: Pages.UserProfile
            },
            {
                key: 'user-edit',
                title: 'User Edit',
                path: '/edit',
                Child: Pages.UserEdit
            }
        ]
    }
];

Hooks

Library has some hooks for eases route state management.

  • useRoutePayload: returns current route payload.

For this route definition:

...

export default [
    {
        key: 'main-page',
        title: 'Main Page',
        path: '/',
        Child: Pages.Main,
        payload: {
            title: 'Main Page'
        }
    },
    ...
];

We can access to it's payload, at '/' path, as below:

import { useRoutePayload } from '@calvear/react-spa-routerizer';

export default function MainPage()
{
    const { title } = useRoutePayload();

    return (
        <div id='main-page'>
            <h1>{title}</h1>
        </div>
    );
}
  • useQueryParams: returns URL query parameters.

  • useHashValue: returns URL hash value.

  • useRouteState: returns current route state, from React Router.

Also, this library exports every hook from 'react-router' - see React Router Hooks for more information.

  • useHistory: gives you access to the history instance that you may use to navigate.

  • useLocation: returns the location object that represents the current URL.

  • useParams: useParams returns an object of key/value pairs of URL parameters.

  • useRouteMatch: attempts to match the current URL in the same way that a would.

Recipes 📖

  • Public and Private routes.
// public.routes.js
import { lazy } from 'react';

const Pages = {
    Login: lazy(() => import('pages/login')),
    Unauthorized: lazy(() => import('pages/unauthorized'))
};

export default [
    {
        key: 'login-page',
        title: 'Sign In',
        path: '/login',
        Child: Pages.Login
    },
    {
        key: 'unauthorized-page',
        title: 'Unauthorized',
        path: '/403',
        Child: Pages.Unauthorized
    }
];
// private.routes.js
import { lazy } from 'react';

const Pages = {
    Main: lazy(() => import('pages/main'))
};

export default [
    {
        key: 'main-page',
        title: 'Welcome to my app',
        path: '/',
        Child: Pages.Main
    }
];
// app.routes.js
import { lazy } from 'react';
import privateRoutes from 'routes/private.routes';
import publicRoutes from 'routes/public.routes';

const Layouts = {
    App: lazy(() => import('layouts/app'))
};

export default [
    {
        key: 'public-router',
        path: '/',
        routes: publicRoutes
    },
    {
        key: 'private-router',
        path: '/',
        routes: privateRoutes,
        Layout: Layouts.App,
        payload: {
            secured: true
        }
    }
];
// App.router.js
import { lazy } from 'react';
import { useRoutePayload, Redirect, Router } from '@calvear/react-spa-routerizer';
import { useIsAuthenticated } from 'security'; // custom security validation

const DefaultPage = lazy(() => import('pages/not-found'));

export default function AppRouter()
{
    const { secured } = useRoutePayload();
    const { authenticated } = useIsAuthenticated();

    if (!secured && authenticated)
        return <Redirect to='/' />;

    if (secured && !authenticated)
        return <Redirect to='/login' />;

    return (
        <Router DefaultChild={ DefaultPage } />
    );
}

You should declare two routes files, and merge them in a main routes file.

Linting 🧿

Project uses ESLint, for code formatting and code styling normalizing.

  • eslint: JavaScript and React linter with Airbnb React base config and some other additions.
  • prettier: optional Prettier config.

For correct interpretation of linters, is recommended to use Visual Studio Code as IDE and install the plugins in .vscode folder at 'extensions.json', as well as use the config provided in 'settings.json'

Changelog 📄

For last changes see CHANGELOG.md file for details.

Built with 🛠️

  • React - the most fabulous JavaScript framework.
  • React Router - React most popular routing library.

License 📄

This project is licensed under the MIT License - see LICENSE.md file for details.


⌨ by Alvear Candia, Cristopher Alejandro