Routing
Why?
- navigating makes the page reload
- without caching it can be slow
- avoid page reloads by using a router
How?
- no official way, but many libraries
react-router
is the most popular- other libraries to consider
navi
promising up-and-comer
Using react-router
- the following is just an overview, the docs are more detailed
Router
- docs
- at top-level
BrowserRouter
for browser docsStaticRouter
for server-side rendering docsMemoryRouter
for testing docs
examples use a custom
Router
based onMemoryRouter
Route
- docs
- matches
path
to components - multiple can be active
- can be nested, side-by-side
- fully dynamic
- can have params
/some/route/:param
Switch
- docs
- ensures that only one
Route
is active at a time - use for fallback (404) routes
Link
Redirect
- docs
- when rendered, redirect to
to
prop - use it to keep old links working
useParams
- docs
- get hold of params in your components
Simple
import React, { FC } from 'react'
import { Route, Switch } from 'react-router'
import { Link } from 'react-router-dom'
export const Simple: FC = () => {
return (
<Switch>
<Route path="/lorem">lorem</Route>
<Route path="/ipsum">ipsum</Route>
<Route path="/dolor">dolor</Route>
<Route path="/">
<h1>Home</h1>
<ul>
<li>
<Link to="/lorem">lorem</Link>
</li>
<li>
<Link to="/ipsum">ipsum</Link>
</li>
<li>
<Link to="/dolor">dolor</Link>
</li>
</ul>
</Route>
</Switch>
)
}
export default <Simple />
404 Page
import React, { FC } from 'react'
import { NavLink, Route, Switch } from 'react-router-dom'
import classes from './example.module.css'
export const NavBar: FC = () => {
return (
<nav>
<NavLink to="/" exact activeClassName={classes.activeLink}>
home
</NavLink>
{' '}
<NavLink to="/pricing" activeClassName={classes.activeLink}>
pricing
</NavLink>
{' '}
<NavLink to="/about" activeClassName={classes.activeLink}>
about
</NavLink>
{' '}
<NavLink
to="/this-page-does-not-exist"
activeClassName={classes.activeLink}
>
broken link
</NavLink>
</nav>
)
}
export const Example: FC = () => {
return (
<div>
<NavBar />
<article>
<Switch>
<Route path="/pricing">pricing page</Route>
<Route path="/about">about page</Route>
<Route path="/" exact>
home page
</Route>
<Route path="/">404 page</Route>
</Switch>
</article>
</div>
)
}
export default <Example />
Using Params
import React, { FC } from 'react'
import { Redirect, Route, Switch, useParams } from 'react-router'
import { Link } from 'react-router-dom'
import { Database } from './database'
export const Article: FC = () => {
const { articleId } = useParams<{ articleId: string }>()
const article = Database.getArticleById(Number(articleId))
const user = article && Database.getUserById(article.owner)
return (
<div>
{user && article ? (
<div>
<h1>{article.title}</h1>
<p>{article.content}</p>
<Link to={`/user/${user.id}`}>
<i>by {user.name}</i>
</Link>
</div>
) : (
<h1>Cannot find article</h1>
)}
</div>
)
}
export const User: FC = () => {
const { userId } = useParams<{ userId: string }>()
const user = Database.getUserById(userId)
const articles = user ? user.articles.map(Database.getArticleById) : []
return (
<div>
{user ? (
<div>
<h1>Posts from {user.name}</h1>
{articles.length ? (
<ul>
{articles.map((article) => {
if (!article) throw new Error()
const { title, id } = article
return (
<li key={id}>
<Link to={`/article/${id}`}>{title}</Link>
</li>
)
})}
</ul>
) : (
<p>{user.name} has no articles</p>
)}
</div>
) : (
<h1>Cannot find user with id {userId}</h1>
)}
</div>
)
}
export const Users: FC = () => {
const users = Database.getUsers()
return (
<div>
<h1>Users</h1>
<ul>
{users.map(({ id, name }) => (
<li key={id}>
<Link to={`/user/${id}`}>{name}</Link>
</li>
))}
</ul>
</div>
)
}
export const Params: FC = () => {
return (
<Switch>
<Route path="/users">
<Users />
</Route>
<Route path="/user/:userId">
<User />
</Route>
<Route path="/article/:articleId">
<Article />
</Route>
<Route path="/">
<Redirect to="/users" />
</Route>
</Switch>
)
}
export default <Params />