TIL/2021–02–11 & 12

Day 63 and 64: Treehouse Full Stack JavaScript Techdegree

React Router 4 Basics Continuation

Navigating between Routes

Currently the app uses anchor elements to display the navigation links

On Header.js

import React from ‘react’;

const Header = () => (

<header>

<span className=”icn-logo”><i className=”material-icons”>code</i></span>

<ul className=”main-nav”>

<li><a href=”#”>Home</a></li>

<li><a href=”#”>About</a></li>

<li><a href=”#”>Teachers</a></li>

<li><a href=”#”>Courses</a></li>

</ul>

</header>

);

export default Header;

On react router we don’t use regular anchor tags to link to the routes in our app. Instead, it provides a more intelligent approach navigating between routes with link

Link component is one of react routers core writing components

First we have to import it

The to attribute is similar to the href attribute — it points the link component to a route by changing the path in the URL

import React from “react”;

import { Link } from “react-router-dom”;

const Header = () => (

<header>

<span className=”icn-logo”>

<i className=”material-icons”>code</i>

</span>

<ul className=”main-nav”>

<li>

<Link to=”/”>Home</Link>

</li>

<li>

<Link to=”/about”>About</Link>

</li>

<li>

<Link to=”/teachers”>Teachers</Link>

</li>

<li>

<Link to=”/courses”>Courses</Link>

</li>

</ul>

</header>

);

export default Header;

— — -

Styling active links

The navigation is now working but when you click it — it does not remain highlighted

A good intuitive navigation gives users visual feedback about which page they’re visiting

React router provides a simple way to change the appearance of a Link when it is active or when its path matches the URL

The NavLink component is a special version of the Link component that can recognize when it matches the current URL so we can style it in a certain way

First, import NavLink

import { NavLink } from “react-router-dom”;

Then

<ul className=”main-nav”>

<li>

<NavLink to=”/”>Home</NavLink>

</li>

<li>

<NavLink to=”/about”>About</NavLink>

</li>

<li>

<NavLink to=”/teachers”>Teachers</NavLink>

</li>

<li>

<NavLink to=”/courses”>Courses</NavLink>

</li>

</ul>

If we inspect the NavLink — NavLink once selected gives a default class called active to the selected link

In CSS we’ve already created an active CSS style if active is present on the component that is why we have a style of background-color Blue

Now as you can see, the Home link is active on all route paths — as you can remember react router considers the / path to be the same as /about /teachers and /courses because it is present on the link. To fix this, we can add an exact prop to the home NavLink so that it would only be active in that exact URL path

<Route exact path=”/” component={Home} />

And now it works — home is only active if we are only on its root path

The NavLink component also lets us assign a custom class to an active link and we are able to define active styles inline

For example, if we want to change the default “active” className

<NavLink to=”/about” activeClassName=”Renzo”>

About

</NavLink>

We can also write active styles directly to the NavLink component using the activeStyle prop

We have to pass it an object that sets the style you want to set

<NavLink to=”/about” activeStyle={{ background: “tomato” }}>

About

</NavLink>

— — —

Routing challenge

Create links to the courses of HTML CSS and JavaScript

Now let’s start

import React from “react”;

import { NavLink, Route } from “react-router-dom”;

//App Components

import HTML from “./courses/HTML”;

import CSS from “./courses/CSS”;

import JS from “./courses/JavaScript”;

const Courses = () => (

<div className=”main-content courses”>

<div className=”course-header group”>

<h2>Courses</h2>

<ul className=”course-nav”>

<li>

<NavLink to=”/courses/html”>HTML</NavLink>

</li>

<li>

<NavLink to=”/courses/css”>CSS</NavLink>

</li>

<li>

<NavLink to=”/courses/javascript”>JavaScript</NavLink>

</li>

</ul>

</div>

{/* Write routes here… */}

<Route path=”/courses/html” component={HTML} />

<Route path=”/courses/css” component={CSS} />

<Route path=”/courses/javascript” component={JS} />

</div>

);

export default Courses;

— — -

Redirecting a route

Right now if we navigate to the courses NavLink we are just sent this. No information whatsoever. We have to select any of the three courses to actually redirect and display the data

What we want to happen is when the user navigates to the courses, he/she should already see a course like HTML without having to select it

One way to fix it is on Header.js and by adding a /courses/html to the link

But the courses active still is automatically removed if we navigate to CSS or JavaScript because the urls does not match /courses/html so it affects NavLink to provide an active class once selected

React router provides an intelligent redirect component that instructs the router to redirect from one route to the other

For example, redirect from /courses to /courses/html

On Courses.js let us first import redirect from react-router-dom

import { NavLink, Route, Redirect } from “react-router-dom”;

<Redirect /> requires a to prop and the value should be the URL to redirect to

<Redirect to=”/courses/html” />

import React from “react”;

import { NavLink, Route, Redirect } from “react-router-dom”;

//App Components

import HTML from “./courses/HTML”;

import CSS from “./courses/CSS”;

import JS from “./courses/JavaScript”;

const Courses = () => (

<div className=”main-content courses”>

<div className=”course-header group”>

<h2>Courses</h2>

<ul className=”course-nav”>

<li>

<NavLink to=”/courses/html”>HTML</NavLink>

</li>

<li>

<NavLink to=”/courses/css”>CSS</NavLink>

</li>

<li>

<NavLink to=”/courses/javascript”>JavaScript</NavLink>

</li>

</ul>

</div>

{/* Write routes here… */}

<Redirect to=”/courses/html” />

<Route path=”/courses/html” component={HTML} />

<Route path=”/courses/css” component={CSS} />

<Route path=”/courses/javascript” component={JS} />

</div>

);

export default Courses;

And it works! But once we click courses again it is blank — we lose our redirect

Since we are redirecting from deeply nested routes, we need to make a few adjustments to keep the URL in sync with the UI

We should override the existing courses route and render a redirect component that will navigate to the new location

So we can create a route that matches the path /courses and render a redirect component

Remember: redirect, route are components as well

<Route

exact

path=”/courses”

render={() => <Redirect to=”/courses/html” />}

/>

— — —

Using the Match Object

When we render a component with a route, React router passes the component additional information about the current path name and the path and the URL the route is matching

Match contains information about how a route is matching the URL

For example the path property lets us know that courses uses the /courses path and the URL property tells us that it is matching the courses portion of the url

We can access the this data from inside components being rendered by routes

The path and url properties are useful when building nested routes and links

Lets use this data to have our courses routes and links dynamically match the current URL and path. That way we don’t have to worry about including a / and if our nested routes and links are going to match the current URL

To access the match data from inside the component

First we’ll pass the match object to the courses function

const Courses = ({ match }) => (

Then pass the NavLinks the portion of the URL to match, which we can access from the url property

<ul className=”course-nav”>

<li>

<NavLink to={`${match.url}/html`}>HTML</NavLink>

</li>

<li>

<NavLink to={`${match.url}/css`}>CSS</NavLink>

</li>

<li>

<NavLink to={`${match.url}/javascript`}>JavaScript</NavLink>

</li>

</ul>

Then on our Route we will do match.path

{/* Write routes here… */}

<Route

exact

path={match.path}

render={() => <Redirect to={`${match.path}/html`} />}

/>

<Route path={`${match.path}/html`} component={HTML} />

<Route path={`${match.path}/css`} component={CSS} />

<Route path={`${match.path}/javascript`} component={JS} />

</div>

So now even if we change the URL on App.js

<BrowserRouter>

<div className=”container”>

<Header />

<Route exact path=”/” component={Home} />

<Route path=”/about” render={() => <About />} />

<Route path=”/teachers” component={Teachers} />

<Route path=”/foo” component={Courses} />

</div>

</BrowserRouter>

Our routes will still work and adjust (look at the URL below)

Note:

For NavLinks we will always access match.url

<NavLink to={`${match.url}`/something} > </NavLink>

For Route we will always access match.path

<Route path={`${match.path}/something`} />

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store