[React]: Router with React Router DOM

React

11/06/2019


More information on React Router DOM can be found here.

1. Install React Router DOM

BASH
npm i react-router-dom

2. Add Browser Router in index.js

JSX
// ...
import { BrowserRouter } from "react-router-dom"
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById("root")
)

Import Browser Router component and wrap it around the App component.

3. Create Route in App.js

Import Route

JSX
import { Route } from "react-router-dom"

Create another page

JSX
const MainPage = () => (
<div>
<h1>MAIN PAGE</h1>
</div>
)
const SecondPage = () => (
<div>
<h1>SECOND PAGE</h1>
</div>
)

Create route

JSX
function App() {
return (
<div>
<Route exact path="/" component={MainPage} />
<Route exact path="page2" component={SecondPage} />>
</div>
)
}

Note: If you don't put exact, it will be rendered in different pages as well which includes the same path.

For example, if you would like to include a navigation bar in all the pages exclude exact tag.

4. Using Switch

Using Switch component prevents from rendering other pages.

import Switch Component

JSX
import { Switch, Route } from "react-router-dom"

Usage

JSX
function App() {
return (
<div>
<Switch>
<Route exact path="/" component={MainPage} />
<Route path="/page2" component={SecondPage} />
</Switch>
</div>
)
}

When a Route is found inside Switch tag, it won't render anything else.

For example, when we have

JSX
<Switch>
<Route path="/" component={MainPage} />
<Route path="/page2" component={SecondPage} />
</Switch>

Then, we go to /page2, it will only show MainPage since MainPage will be rendered and it doesn't render others.

Creating Dynamic routing

Nested routes

Creating nested routes is possible with the following.

First, create more sub page

JSX
const SubPage = () => {
return (
<div>
<h1>SUB PAGE</h1>
</div>
)
}
JSX
function App() {
return (
<div>
<Route exact path="/" component={MainPage} />
<Route exact path="/page2" component={SecondPage} />
<Route path="/page2:pageId" component={SubPage} />
</div>
)
}

:pageId is a URL parameter. It shows the pages that match dynamically. For example, it will show the SubPage for any url: /page2/*

props components

props has different components:

  • props.match
  • props.history
  • props.location

We can show which url that's visited with

JS
const SubPage = props => {
return (
<div>
<h1>SUB PAGE: {props.match.params.pageId}</h1>
</div>
)
}

For example, when we visit

TEXT
localhost:3000/page2/asdfasdf

It will show on page:

TEXT
SUB PAGE: asdfasdf

This allows the sub page to populate itself. This may be useful to retrieve data from back end.

JSX
import { Route, Link } from "react-router-dom"
JSX
const SecondPage = props => (
<div>
<Link to="/page2/100">To Sub Page 100</Link>
<h1>SECOND PAGE</h1>
</div>
)

Note: React is SPA. This does not redirect and rebuild the entire application, but rather, it determines which part of the DOM to use.

This would be similar to using:

JSX
<button onClick={() => props.history.push("/asdf")}>Click</button>

By using a props component it'd be more efficient to use it as:

JSX
const SecondPage = props => (
<div>
<Link to={`${props.match.url}/100`}>TO SUB PAGE 100</Link>
<Link to={`${props.match.url}/222`}>TO SUB PAGE 222</Link>
<Link to={`${props.match.url}/7`}>TO SUB PAGE 7</Link>
<h1>SECOND PAGE</h1>
</div>
)

This is useful when you want to re-use sub page that isn't from page2.

For example:

JSX
function App() {
return (
<div>
<Route exact path="/" component={MainPage} />
<Route exact path="/page2" component={SecondPage} />
<Route path="/page2:pageId" component={SubPage} />
<Route exact path="/asd/asd" component={SecondPage} />
<Route path="/asd/asd/:pageId" component={SubPage} />
</div>
)
}

SecondPage and SubPage components can be re-used in different links in /asd/asd.

withRouter

As we've imported React Route in our app class, in order for sub-component to use it, it would have to pass down props.history. However, there may be situation where you have to pass down the props.history multiple times--this inefficiency is called prop tunneling/drilling.

To prevent this, in the children that needs props.history, use the component withRouter.

Usage

JSX
import { withRouter } from "react-router-dom"
// ...
export default withRouter(ChildComponent)

withRouter is a higher order component, function that takes any component as argument and returns a modified component.

i.e. the child component gets access to props.history

In the child component, access with

JSX
<div
className=''
onClick={() => history.push(...)}
>

WRITTEN BY

Keeping a record