← Back
react react-tapas

React Tapas 6: Router part 2

Some missing pieces of Router from latest session:

To add links from one page to another we can't use <a> directly because it triggers a new page reload. A <Link> convenience component is provided from react-router library:

const HomePage = () => {
return (
<div>
<Link to="/about">About us</Link>
</div>
)
}

2. Route params #

We can define route params in the router using the :param syntaxis:

const Router = () => {
return (
<BrowserRouter>
<Switch>
<Route exact path="posts">
<PostListPage />
</Route>
<Route exact path="post/:id">
<PostDetailPage />
</Route>
</Switch>
</BrowserRouter>
)
}

We can access the parameters using the "useParams" hook, that returns an object with all parameters:

const PostDetailPage = () => {
const params = useParams()
return (
<div>
<h1>Post id: {params.id}</h1>
</div>
)
}

Notice that, with typescript, we need it's better to type the parameters:

const params = useParams<{ id: string }>()

3. Imperative API #

Sometimes (almost never) we need to change the history directly (without using Link(s)). For example, navigating when pressing a button (a bad practice, by the way).

For those scenarios, we can use "useHistory" hook:

const HomePage = () => {
const history = useHistory();
return (
<button onClick={ () => history.push('/about') }>
Visit about
</button>
)
}

4. Redirects #

It's tempting to use the imperative API to make page redirects.

Use component instead:

const PostDetailPage = () => {
const user = useCurrentUser();

if (!user) return <Redirect to="/login" />

return <div>Only visible if there's a user session</div>
}

Just pass the footer to the Layout in props:

const Layout = ({ title, children, footer }) => {
return (
<div>
<header>
<h1>{title || 'Sin título'}</h1>
</header>
{children && <main>{children}</main>}
{footer && <footer>{footer}</footer>}
</div>
)
}

Usage:

const AboutPage = () => (
<Layout title="About" footer={<div>Búscanos en twitch</div>}>
Hola
</Layout>
)

Corollary: The most difficult of React dev is not to over-engineer.

Note: What React renders #

the following line:

      {children && <main>{children}</main>}

means: "if there's children, render it (wrapped by a main)".

It is almost equivalent to:

      {children ? <main>{children}</main> : null}

"if theres a children, render it (wrapped by a main), otherwise render nothing"

This work because React does not render when it receives null, undefined or false.

You have to be careful, tho.

For example:

{list.length && <ul>...</ul>}

This will render a "0" if the list is empty.

There are two alternatives:

{list.length > 0 && <ul>...</ul>}

or:

{list.length ? <ul>...</ul> : null}

By the way, Kent recommends not to use &&. I disagree (I think is easier to read than ternary and more concise. But is good to know the problems)