Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/axtk/react-keenrouter

React router with componentless route matching
https://github.com/axtk/react-keenrouter

history-api react-hooks react-router router spa

Last synced: 2 months ago
JSON representation

React router with componentless route matching

Awesome Lists containing this project

README

        

[![npm](https://img.shields.io/npm/v/react-keenrouter?labelColor=royalblue&color=royalblue&style=flat-square)](https://www.npmjs.com/package/react-keenrouter) [![GitHub](https://img.shields.io/badge/-GitHub-royalblue?labelColor=royalblue&color=royalblue&style=flat-square&logo=github)](https://github.com/axtk/react-keenrouter) ![React](https://img.shields.io/badge/%23-React-345?labelColor=345&color=345&style=flat-square) [![SSR](https://img.shields.io/badge/%23-SSR-345?labelColor=345&color=345&style=flat-square)](#server-side-rendering-ssr) ![TypeScript](https://img.shields.io/badge/%23-TypeScript-345?labelColor=345&color=345&style=flat-square)

# react-keenrouter

*React router with componentless route matching*

## Features

- componentless route matching
- doesn't enforce route collocation and tight coupling within a route hierarchy;
- works the same way both for components and dynamic route-based prop values;
- is akin to the common React pattern of [conditional rendering](https://react.dev/learn/conditional-rendering);
- the history-based route link components `` and `` with the props similar to those of the ordinary HTML link elements `` and `` (allowing for quick migration back and forth and working more like a polyfill to ordinary links);
- the `` component fit for both browser and server rendering;
- the utility converting plain HTML links (that can't be easily replaced with React components) to history-based links.

## Example

```jsx
import {A, useRoute} from 'react-keenrouter';

const appRoutes = {
HOME: '/',
INTRO: '/intro',
SECTION: /^\/section\/(?\d+)\/?$/,
};

const allKnownRoutes = Object.values(appRoutes);

export const App = () => {
// the `useRoute()` hook subscribes the component to URL changes
let [route, withRoute] = useRoute();

return (



{/* the route link component `A` looks similar to the
plain HTML link as it serves a similar purpose */}

Home

{' | '}

Intro


{withRoute(
appRoutes.HOME, (

Home




),
)}
{/* although `withRoute()` calls may appear in groups like
in this example, they work independently from each other
and may as well be used uncoupled in different places of
an application */}
{withRoute(
appRoutes.INTRO, (

Intro



),
)}
{/* the second and the third parameter of `withRoute()` can
be functions of `{href, params}`, with `params`
containing the capturing groups of the location pattern
if it is a regular expression */}
{withRoute(appRoutes.SECTION, ({params}) => (

Section #{params.id}



))}
{/* below, rendering `null` if the current location
matches `allKnownRoutes`, and the 404 error screen
otherwise */}
{withRoute(
allKnownRoutes,
null, (

404 Not found



),
)}



{
// `route` has a `window.location`-like API and can
// be handy for direct manipulation of the location
route.assign(appRoutes.HOME);
}}
>
Home



);
};
```

```jsx
import {createRoot} from 'react-dom/client';
import {App} from './App';

createRoot(document.querySelector('#app')).render();
```

The `route` object returned from the `useRoute()` hook is an instance of the [`NavigationLocation`](https://www.npmjs.com/package/navloc) class provided by the wrapping `` component. If there is no `` up the React node tree (like with `` in the example above), a default `route` based on the current page location is used. A wrapping `` can be useful to provide a custom `route` prop value that accepts either a string location or a `NavigationLocation` class instance.

## Custom routing

The default `route` object returned from the `useRoute()` hook responds to changes in the entire URL, with `pathname`, `search`, and `hash` combined. This can be changed by providing an instance of a [customized](https://www.npmjs.com/package/navloc#custom-behavior) extension of the `NavigationLocation` class to the `Router` component.

```js
import {NavigationLocation} from 'react-keenrouter';

export class PathLocation extends NavigationLocation {
deriveHref(location) {
// disregarding `search` and `hash`
return getPath(location, {search: false, hash: false});
}
}
```

```jsx
import {createRoot} from 'react-dom/client';
import {Router} from 'react-keenrouter';
import {PathLocation} from './PathLocation';

createRoot(document.querySelector('#app')).render(


,
);
```

Extending the `NavigationLocation` class gives plenty of room for customization. This approach allows in fact to go beyond the URL-based routing altogether.

## Server-side rendering (SSR)

For the initial render on the server, the `` component can be used to pass the current route location to the application in essentially the same way as it can be done in the client-side code:

```jsx
// On the Express server
app.get('/', (req, res) => {
let html = ReactDOMServer.renderToString(
,
);

// Sending the resulting HTML to the client.
});
```

## Converting plain links

The `useRouteLinks()` hook can be helpful when it's necessary to convert plain HTML links to SPA route links if the route link component is not applicable right away (for instance, in a server-fetched static chunk of HTML content):

```js
useRouteLinks(containerRef, '.content a');
// `containerRef` is a value returned from the React's `useRef()` hook.
```