Smoke and Mirrors: Working with React Router

Nick Diaz
4 min readJul 15, 2021

React is a fascinating tool in frontend development. It’s a powerful and versatile framework with a wide array of features allowing developers complete control in creating their applications, and an equally wide array of libraries that provide even more power and creative freedom. One of those libraries is React Router.

React Router can essentially create the illusion that a user is navigating to a different page when clicking a link. It even changes what displays in the address bar of the user’s web browser! In actuality though, the user hasn’t left the initial page at all. An entire web application built with React Router can be housed within a single page of HTML. React Router allows this by changing which React components render on the page rather than redirecting to a new page entirely.

After creating the application and installing the React Router library, including a <BrowserRouter> component in the return statement or render method of your App will allow the components placed inside of it to access to React Router’s functionality.

import { BrowserRouter as Router } from 'react-router-dom';function App() {return(<Router><div className="App">
<MyComponent />
</div>
</Router>)}

Here, we name the BrowserRouter component as simply Router for simplicity’s sake. In this case, MyComponent will have access to React Router. Now, what’s next? How do we give our user the ability to change what they see? Enter the Switch and Route components.

import {
BrowserRouter as Router,
Switch,
Route } from 'react-router-dom'
function App() {return(<Router>
<div className="App">
<Switch><Route exact path='/'>
<MyComponent />
</Route>
<Route path='/other'>
<OtherComponent />
</Route>
</Switch></div>
</Router>
)}

What’s happening here? Well, our application is wrapped in the <Router> component, like before. However, now our <Switch> component will allow us to change what renders on the page based on the address the user enters. If the user enters the root path /, <MyComponent /> will render, while entering the/other path will display<OtherComponent />. The <Switch> component will match the chosen path with the path attribute of its <Route> components to determine which one to render. It will match based on the first thing it reads, so we use the exact keyword to ensure that it only renders the root path when the user specifically wants the root path. Without it, even entering /other would make the <MyComponent /> render instead of what we actually want, the <OtherComponent />.

What if we want part of the page, like a navigation bar, to persist through these changes and remain visible all the time? That’s possible with Router as well.

import {
BrowserRouter as Router,
Switch,
Route } from 'react-router-dom'
function App() {return(<Router>
<div className="App">
<header className="App-header">
</header>
<main>
<Switch>
<Route exact path='/'>
<MyComponent />
</Route>
<Route path='/other'>
<OtherComponent />
</Route>
</Switch>
</main>
</div>
</Router>
)}

Because our header is outside of the <Switch>, it and anything we put inside it will stay rendered on the page, even when the user selects a new route.

Great! Now we’re changing what the user sees without needing an entirely new HTML file. But, we’re not quite done yet. We don’t want to make the user write out a new address every time they want to see something else; it’s much easier to just click something. React Router’s <Link> component will take care of this for us.

import {
BrowserRouter as Router,
Switch,
Route,
Link } from 'react-router-dom'
function App() {return(<Router>
<div className="App">
<header className="App-header"><Link to='/'>Link to My Component</Link>
<Link to='/other'>Link to Other Component</Link>
</header><main>
<Switch>
<Route exact path='/'>
<MyComponent />
</Route>
<Route path='/other'>
<OtherComponent />
</Route>
</Switch>
</main>
</div>
</Router>
)}

These <Link> components will generate an element similar to a standard <a> tag in the DOM. Instead of redirecting to another website, however, these elements correspond to the <Route>s in the <Switch> component to render new components as the user wants.

What if we want to go to a different route, but don’t want to have to click a link to do it? For example, what if we wanted to click a button in the <MyComponent> that will send us to our <OtherComponent>? React Router still has this covered with its <Redirect> component.

import { Redirect } from 'react-router-dom'function MyComponent() {
const [toOther, setToOther] = React.useState(false)
if (toOther === true) {
return <Redirect to='/other'>
}
return(
<div>
<button onClick={() => toOther(true)}>Redirect to Other</button>
</div>
)}

Here, our <MyComponent> renders a button. Clicking that button runs a callback function that triggers a state change, setting the toOther attribute of <MyComponent> to true. Once the component re-renders after the state change, our if statement will now evaluate to true, and the <Redirect> component is returned. This component immediately navigates to the new corresponding route back up in our <Switch>, and the user sees <OtherComponent>, without actually clicking a link! This pattern can be repurposed to other events in your application, like submitting a form.

React Router is invaluable in smoothly and efficiently getting around your React applications. It is well worth spending time to familiarize yourself with this library to make your user’s experience all that much cleaner.

--

--