React Space Router
Space Router bindings for React
React Space Router is a set of hooks and components for keeping your app in sync with the url and performing page navigations. A library built by and used at Humaans.
- React hooks based
- Nested routes
- Async navigation middleware
- Built in query string parser
- Supports external stores for router state
- Scrolls to top after navigation
- Preserves cmd/ctrl/alt/shift click and mouse middle click
Why
“Perfection is achieved when there is nothing left to take away.” React Space Router is built upon Space Router, a framework agnostic tiny core that handles url listening, route matching and navigation. React Space Router wraps that core into an idiomatic set of React components and hooks. The hope is you’ll find React Space Router refreshingly simple compared to the existing alternatives, while still offering enough extensibility.
Install
$ npm install react-space-router
Example
import React from 'react'
import { Router, Routes, Link, useRoute, useNavigate } from 'react-space-router'
const routes = [
{ path: '/', component: Home },
{
component: SettingsContainer,
routes: [
{ path: '/settings', component: Settings },
{ path: '/settings/billing', component: Billing },
],
},
]
function App() {
return (
<Router>
<Routes map={routes} />
</Router>
)
}
function Home() {
const { pathname, params, query } = useRoute()
return (
<div>
<h1>Home</h1>
<Link href='/settings'>Settings</Link>
</div>
)
}
function Settings({ tag }) {
const navigate = useNavigate()
useEffect(() => {
navigate({ url: '/settings/billing' })
}, [])
return (
<div>
<h1>Settings</h1>
<Link href='/'>Home</Link>
</div>
)
}
API
<Router />
The application needs to be wrapped in the Router component to provides the router context and state.
Props:
modeone ofhistory,hash,memory, default ishistoryqsa custom query string parser, an object of shape `{ parse, stringify }useRoutea custom hook for subscribing to current route state. If this is provided, the router will assume you’re storing the latest router state passed to you viaonNavigatedcallback and will allow subscribing to this state via this custom hookonNavigating(nextRoute)called when navigation starts, can be an async function which case the router will await before proceeding to finalise the transition and callonNavigated, note if a new navigation is started while this function is processing,onNavigatedwill no longer be called for this specific navigation, instead the next navigation kicks on and repeats the same sequenceonNavigated(route)called when navigation completed
<Routes />
<Routes routes={[{ path: '/', component: Home }]}>
Render the components that match the current route based on the route config.
Props:
routesan array of arrays of route definitions, where each route is an object of shape{ path, component, props, redirect, scrollGroup, routes, ...metadata }pathis the URL pattern to match that can include named parameters as segmentscomponenta react component to render, can be a component wrapped in React.lazypropsprops to be passed to the componentredirectcan be a string or a function that redirects upon entering that routescrollGroupa string that can group a set of routes, such that navigating between them does not scroll to top, by default each route is in it’s own scroll grouproutesis an array of nested route definitions...metadataall other other keys can be chosen by you
disableScrollToTopdisable the scroll to top behaviour after each navigation
<Link />
<Link href='/profile/32' className='nav' replace />
Renders an <a> link with a correct href and onClick handler that will intercept the click and push a history entry to avoid full page reload. Preserves cmd + click behaviour.
Props:
hrefnavigation target, can be astringor anobjectwith:pathnamethe pathname portion of the target url, which can include named segmentsparamsparams to interpolate into the named pathname segmentsquerythe query object that will be passed throughqs.stringifyhashthe hash fragment to append to the url of the urlmergemerge partialtoobject into the current route
replaceset to true to replace the current entry in the navigation stack instead of pushingcurrentset to true to render link as current page, or false to disable auto current page detection based on the current URLclassNamecan be a function that takesisCurrentif the current route is activestylecan be a function that takesisCurrentif the current route is activeextraPropsa function that takesisCurrentif the current route is active
The rest of the props are spread onto the <a> element.
<Navigate />
<Navigate to={{ pathname: '/' }} />
Redirect to the target url upon rendering this component.
Props:
tocan be astringor anobject(refer tonavigatebelow)
useInternalRouterInstance
const router = useInternalRouterInstance()
Get the Space Router instance. See space-router docs for details. Should typically not be necessary to use it directly. All relevant functionality is available via the other hooks.
useRoute
const route = useRoute()
Subscribe to the current route. Route is an object of shape { url, pathname, params, query, search, hash, pattern, data }.
urlfull relative url string including query string and hash if anypathnamethe pathname portion of the target url, which can include named segmentsparamsparams extracted from the named pathname segmentsqueryquery object that was parsed withqs.parsesearchfull unparsed query stringhashhash fragmentpatternthe matched route pattern as defined in the route configdataan array of nested matched route objects with componentns and any additional metadata found in the route config
useNavigate
const navigate = useNavigate()
// examples
navigate('/shows')
navigate({ url: '/show/1' })
navigate({ url: '/show/2', replace: true })
navigate({ pathname: '/shows', query: { 'most-recent': 1 } })
navigate({ query: { 'top-rated': 1 }, merge: true })
navigate({ query: { 'top-rated': undefined }, merge: true })
Get the navigate function for performing navigations. Navigate takes a string url or an object of shape:
urlurl stringpathnamethe pathname portion of the target url, which can include named segmentsparamsparams to interpolate into the named pathname segmentsquerythe query object that will be passed throughqs.stringifyhashthe hash fragment to append to the url of the urlmergemerge partialtoobject into the current routereplaceset to true to replace the current entry in the navigation stack instead of pushing
useLinkProps
const linkProps = useLinkProps(to)
<a {...linkProps} />
Get linkProps that you can spread onto your own links to make them render both href, but also handle clicks to perform navigations using the router. Link props is an object of shape { href, aria-current, onClick}.
Takes a string url or an object of shape:
pathnamethe pathname portion of the target url, which can include named segmentsparamsparams to interpolate into the named pathname segmentsquerythe query object that will be passed throughqs.stringifyhashthe hash fragment to append to the url of the urlmergemerge partialtoobject into the current routereplaceset to true to replace the current entry in the navigation stack instead of pushingcurrentset to true to render link as current page, or false to disable auto current page detection based on the current URLonClicka click handler to be called before the navigation takes place
useMakeHref
const makeHref = useMakeHref()
makeHref(to)
Create a relative url string to use in <a href> attribute.
toobject of shape{ pathname, params, query, hash }. Theparamswill be interpolated into the pathname if the pathname contains any parametrised segments. Thequeryis an object that will be passed throughqs.stringify.
Note: to can be a string, in which case href simply returns the input. Similarly, to can contain { url } key in which case href returns that url. This is to align the function signature with that of navigate so that two can be used interchangeably.
shouldNavigate
shouldNavigate(e)
Check if the current click event should cause a history push, or should be handled by the browser. Used internally by the <Link /> component when intercepting click events to let browser handle:
- cmd/ctrl/alt/shift + click
- middle mouse click
- stop navigation if
e.defaultPreventedis true