A reasonable (and reasonably simple) router for React.
resonable-router
is pretty old-fashioned, because it is built upon the idea
that a single URL corresponds to a specific view. This works well with server rendering,
where that statement holds true. If you don't need server rendering and you are feeling modern,
something like Junctions might be worth a look.
The route of development is driven by a set of goals and non-goals.
With npm:
$ npm install --save reasonable-router
Or with yarn:
$ yarn add reasonable-router
Then you can use the library like you would with everything else (such as with webpack, babel or create-react-app):
import React, { Component } from 'react';
import { BrowserRouter, Link, RouterMountpoint } from 'reasonable-router';
const NotFound = ;
const routeConfig = {
routes: {
'/': { component: () => <h1>Index</h1> },
'/about': { component: () => <h1>About</h1> },
}
miss: () => <h1>Not found :(</h1>
};
class App extends Component {
render() {
return (
<BrowserRouter routeConfig={routeConfig}>
<div>
<Link href='/'>Index</Link> | <Link href='/about'>About</Link>
<RouterMountpoint />
</div>
</BrowserRouter>
);
}
}
export default App;
- Reasonably simple to comprehend and understand
- Single-pass server side rendering
- 404 routes
- Hot reloading that just works
- Nested routes
- Nested 404-routes
- A controlled router (where i.e. Redux manages the router state completely)
- Asynchronous fetching of route components
- Component based routing (
<Route ... />
) - Asynchronous routes
The router to be used in (modern) browsers.
Required props:
routeConfig
: The route configuration object. See the section on Route Configuration.children
: What will ultimately be rendered by the router. Should probably contain a<RouterMountpoint />
somewhere.
The router to be used on the server.
Required props, in addition to the ones from <BrowserRouter>
:
location
: The location to be rendered. Fromreq.originalUrl
(if using Express) or something similar.
Optional props:
onMiss
: A callback that will be called if no route matches. Can be used to communicate with the server renderer to return the proper HTTP status code.
Where the matched route from the router will be rendered. This allows you to
nest the target in other components, i.e. in larger page containers. Allows you
to have the router as the outermost component, which in turn allows you to use
<Link>
and <Fragment>
where you need it.
Doesn't accept props.
A simple wrapper around an <a>
-tag that uses the
pushState
API from the router.
Required props:
- Either
href
orto
: The target to navigate to.href
is a static link target that we know and love from regular<a>
tags.to
is a name of a route to link to. children
: What the<a>
tag will be wrapped around.
A way to add route specific fragments anywhere in your app. Similar to <Match>
from react-router@v4
and <Fragment>
from redux-little-router
.
Required props:
forRoute
: The URL for which the fragment should be rendered. Can contain patterns.children
: What will be rendered if the route matches.
The routes
object used to render the proper component takes on the form of a
map of strings to objects. These objects must contain a component
property.
The component
is what will be rendered when a route matches.
The keys of the routes
property corresponds to the routes. The keys can be
plain text (/some-page
) or contain patterns (as described in the
route-parser
documentation).
The miss
property is the component that will be rendered if no route matches.
The first route that matches the current location will be rendered. So put the most specific routes first in the configuration.
If the route contains paramters (i.e. /route/:param
), they will be passed to
the rendered component in the params
prop.
The following is an example of a route config:
const routeConfig = {
routes: {
'/': { component: () => <h1>Frontpage</h1>) },
'/about': { component: About },
'/hello/:name': { component: ({ params }) => <h1>Hello, { params.name }</h1> }
},
miss: () => <h1>Not found</h1>,
};
Contributions are very welcome!
I feel some parts of the code are in need of refactoring, in particular the parameterized route
matching and passing of parameters, that is currently taking place in both <Router>
and <Fragment>
.
Additionally, testing both needs the chore of setup as well as writing of specifications.