Crossroad
A routing library for React with a familiar interface. It has some differences with React Router so you write cleaner code:
- The links are plain
<a>
instead of custom components. Read more. - There are useful hooks like
useUrl
,useQuery
, etc. - The
<Route>
path isexact
by default and can match query parameters. - It's just ~1.5kb (min+gzip) instead of the 17kb of React Router(+Dom).
Getting Started
Create a React project (npx create-react-app demo
) and install Crossroad:
Then import it on your App.js and define some routes:
Then let's add some navigation and the actual pages:
Now you can start your project and test it by visiting http://localhost:3000/
and http://localhost:3000/login
:
See the more complete working example in this CodeSandbox.
API
The API is composed of these parts:
<Router />
: the top-level component that should wrap your whole app.<Switch />
: renders only the first child that matches the current url.<Route />
: filters whether the given component should be rendered or not for the current URL.<Redirect />
: takes the user to a different URL if it's rendered.<a />
: a plain HTML link, use it to navigate between pages.useUrl()
: a hook that returns the current URL and a setter to update it.usePath()
: a hook that returns the current path and a setter to update it.useQuery()
: a hook that returns the current query and a setter to update it.useHash()
: a hook that returns the current hash and a setter to update it.useParams()
: a hook that extracts params form the current path.
Router
is the default export, <a>
is not exported since it's just the plain link element, and everything else are named exports:
<Router />
The top-level component that has to wrap everything else. Internally it's used to handle clicks, history, etc. It's also the default export of the library:
You would normally setup this Router straight on your App, along things like Statux's or Redux's Store, error handling, translations, etc.
<Switch />
A component that will only render the first of its children that matches the current URL. This is very useful to handle 404s, multiple routes matching, etc. For example, if you have a username system like "/:username"
but want to have a help page, you can make it work easily with the switch:
It is also very useful for 404s:
The <Switch>
component only accepts <Route>
or <Redirect>
as its children.
<Route />
This component defines a conditional path that, when strictly matched, renders the given component. Its props are:
path
: the path to match to the current browser's URL. It can have parameters/:id
and a wildcard at the end*
to make it a partial route.component
: the component that will be rendered if the browser's URL matches thepath
parameter.render
: a function that will be called with the params if the browser's URL matches thepath
parameter.children
: the children to render if the browser's URL matches thepath
parameter.
So for example if the path
prop is "/user"
and you visit the page "/user"
, then the component is rendered; it is ignored otherwise:
When matching a path with a parameter (a part of the url that starts with :
) it will be passed as a prop straight to the children:
NOTE: the parameter is passed straight to the component instead of wrapped like in React Router.
The path can also include a wildcard *
, in which case it will perform a partial match of everything before itself. It can only be at the end of the path:
NOTE: in Crossroad the paths are exact by default, and with the wildcard you can make them partial matches. So the wildcard is the opposite of adding
exact
to React Router.
It can also match query parameters:
<Redirect />
Go to the given url when this component is rendered. It should be used with a Switch
:
This way, when nothing else is matched in the Switch, then the redirect will be triggered and go to the homepage (/
) or any other url we want.
<a>
Links with Crossroad are just traditional plain <a>
. You write the URL and a relative path, and Crossroad handles all the history, routing, etc:
An important concept to understand is where links open, whether it's a react navigation or a browser page change:
/
: plain paths will navigate within React/?abc=def
: queries, hashtags, etc. will also perform a navigation in Reacthttps://example.com/
: full URLs will trigger a browser page changetarget="_self"
: will trigger a browser page change, in the same tabtarget="_blank"
: will open a new tab
Some examples:
useUrl()
NOTE: within Crossroad's and for lack of a better name, "URL" refers to the combination of path + search query + hash.
Read and set the full URL:
These are the structures of each:
url
: an object with the properties, it's similar to the native URL:url.href
: a string with the full URL (path + query + hash)url.path
: a string with the current pathnameurl.query
: an object with the keys and values. Example:{ q: 'hello' }
,{ q: 'hello', s: 'world' }
.url.hash
: the hashtag, without the "#"
setUrl()
: a setter in the React Hooks stylesetUrl("/newpath?search=hello")
: a shortcut with the stringsetUrl({ path: '/newpath' })
: set the path (and delete anything else if any)setUrl({ path: '/newpath', query: { hello: 'world' } })
: update the path and query (and delete the hash if any)setUrl(prev => ...)
: use the previous url (object)
The resulting url
is an object containing each of the parts of the URL:
You can also set it fully or partially:
useUrl()
is powerful enough for all of your needs, but you might still be interested in other hooks to simplify situations where you do e.g. heavy query manipulation with useQuery
.
By default setUrl()
will create a new entry in the browser history. If you want to instead replace the current entry you can pass a second parameter with { mode: 'replace' }
:
usePath()
Read and set only the path(name) part of the URL:
Note: this only modifies the path(name) and keeps the search query and hash the same, so if you want to modify the full URL you should instead utilize
useUrl()
andsetUrl('/welcome')
By default setPath()
will create a new entry in the browser history. If you want to instead replace the current entry you can pass a second parameter with { mode: 'replace' }
:
useQuery()
Read and set only the search query parameters from the URL:
If you pass a parameter, it can read and modify that parameter while keeping the others the same. This is specially useful in e.g. a search form:
When you update it, it will clean any parameter not passed, so make sure to pass the old ones if you want to keep them or a new object if you want to scrub them:
setQuery
only modifies the query string part of the URL, keeping the path
and hash
the same as they were previously.
By default setQuery()
will create a new entry in the browser history. If you want to instead replace the current entry, so that the "Back" button goes to the previous page, you can pass a second parameter with { mode: 'replace' }
:
useHash()
Read and set only the hash part of the URL:
By default setHash()
will create a new entry in the browser history. If you want to instead replace the current entry you can pass a second parameter with { mode: 'replace' }
:
useParams()
Parse the current URL against the given reference:
It's not this method responsibility to match the url, just to attempt to parse it, so if there's no good match it'll just return an empty object (use a <Route />
for path matching):
Examples
Static routes
Vanity URLs
Search page
Query routing
Not found
Github hosting
NOTE: this is a bad idea for SEO, but if that doesn't matter much for you...
React Router diff
This part of the documentation tries to explain in detail the differences between Crossroad and React Router (Dom). Crossroad goal is to build a modern Router API from scratch, removing the legacy code and using Hooks natively.
Remove imperative API
With React Router your component receives the props history
. This is no longer needed with Crossroad; instead of handling the history details, we provide a hook useUrl()
with the setter setUrl()
where you can set the new URL straight away:
The other hooks, like useQuery()
, behave in a similar way so you don't need to be concerned about the history API.
Useful Hooks
I've seen in multiple codebases people end up creating a useQuery()
hook wrapping useLocation
and useHistory
to work with query parameters. Fear no more, this and some other useful hooks are there already on Crossroad and you can use them straight away:
Plain Links
To add a link in your application, you use the native <a>
element instead of having to import a different component. What's more, this makes links a lot more consistent than in React Router. Some examples:
The same in React Router are like this, note the inconsistencies of some times using <Link>
and some times using <a>