5 Remarkable React Router Features (Anchor Links, Query Params & more)
Tags: react, webdev, javascript, programming
Published: 2021-01-11 14:15:37

#Overview 

I love React Router and how it truly expands the use case for React. Today we will take a quick look at what it does and then dive into 5 features and tricks that I feel are pretty remarkable.

<a name="questions"></a>
#### Route to a section:

* [Refresher on React Router](#refresher)

* [Remarkable Features & Tricks](#features)
  1. [Fixing Anchor Links](#anchorLinks)
  2. [Building Relative Paths](#relative)
  3. [Passing Props via `withRouter()`](#withRouter)
  4. [Passing Data via URL Query Params](#queryParams)
  5. [Styling Active Links](#activeLinks)

* [Resources](#resources)


<a name="refresher"></a>
## Refresher

####What is it?
React Router is a game-changing package that allows us to turn our React SPA (single page application), into a virtual "multi-page" experience. 

####Why do we need it?
Typically when we navigate to a new page, the client (browser) sends a request to the server and indicates that a particular route (page) needs to be accessed. (For example, the `/about` route would deliver the `about.html` file.)

However, React is anything but typical and operates only on the client-side. Therefore we can't request a new page from the server, because we only have access to the `index.html` file. So we need a way to at least mimic multiple pages in our SPAs.

####What does it do?
React Router intercepts this request on the client-side and instead renders a new component that we specify. 

For example, it would render a component called `<AboutPage />` which in turn holds `<Bio />` and `<Skills />` children components that make up the content of that "page".

It looks like we went to a new "About" page, with a new URL slug* and content. In reality, we are still in our trusty `index.html` file with its content being rapidly replaced based on routing. 🤯

> *The slug follows the main domain and explains what the page is: website.com/this-is-the-slug

*Completly new to React Router? [Check out the resource links](#resources) at the bottom to get started on the basics first.* 

[Back to 🔝](#questions)

---

<a name="features"></a>
## Remarkable Features & Tricks

<a name="anchorLinks"></a>
### 1️⃣ Fixing Anchor Links

Ok, this is more of a trick than a feature, but you would think creating an anchor link should be simpler than it is. 

A logical assumption would be that `<Link to='/about#skills'>` would take us to the `<About />` component and auto-scroll to the "skills" section. 

Sadly this doesn't work out of the box, but there is a [simple add-on package](https://www.npmjs.com/package/react-router-hash-link) that comes to the rescue.

1. `$ npm install --save react-router-hash-link`

2. Import the package into your component.

3. `<Link>` now accepts a hash anchor URL 🎉

```jsx
...
import { HashLink as Link } from 'react-router-hash-link';

<Link to='/about#skills'>Skills</Link>
```


[Back to 🔝](#questions)


---

<a name="relative"></a>
### 2️⃣ Building Relative Paths

There comes a time when we need to nest routes within other components. For example, linking to a blog post within a certain category. 

Our target URL should look like: `website.com/pets/catsvsdogs`

The problem is that React Router will direct you to the main domain `website.com/catsvsdogs` and **not** append the post slug to the `/pets/` category as shown above. 

This is because by default it treats anything you are linking to as an Absolute path. What we really need is a path relative to the page you are on. 

#### Hard-Code Solution 👎

Hard-coding a relative path is not recommended because if you ever change the parent(s) route further up the URL slug, the path would break. 

```jsx
// Hard-coding the category and post slugs
<Link to='/pets/catsvsdogs'>Cats vs Dogs</Link>
<Route path='/pets' component={blogPost}/>

// The above will break if we make this change to the route
<Route path='/animals' component={blogPost}/>
```

#### Dynamic Solution (Hooks) 👍

A much better solution is to leverage the `url` property from the `match` object that each `<Route />` has. This allows us to dynamically place the current route's URL within the `<Link />`. and `<Route />`.

The `useRouteMatch()` hook lets us destructure the  `url` and the `path` properties from the `match` object. 

> The `path` property is similar to the `url`, but is used with `<Routes />`.

To make everything truly dynamic, let's also convert the above code into a map that generates a `postId` as part of the `<Link>` URL parameters. Then we will set up the `<Route />` to accept any id, by adding `/:postId` at the end of its path.   

```jsx
import { Route, Link, useRouteMatch } from 'react-router-dom';

// Custom Hook
const {path, url} = useRouteMatch();

// Dynamic list of blog post links.
<ul>
  {postsArray.map(({id, name}) => (
   <li key={id}>
     <Link to={`${url}/${id}`}>{name}</Link>
   </li>
  ))}
</ul>

// Route uses the path property to tell which URL it should match and accepts a dynamic id
<Route path={`${path}/:postId`} component={blogPost}/>
```


#### Dynamic Solution (Classes) 👍

With class-based components, we can essentially take the same process as above. Instead of using a hook, we access the `url` in the `match` object via props. 

```jsx
import { Route, Link } from 'react-router-dom';

// Dynamic list of blog post links.
<ul>
  {postsArray.map(({id, name}) => (
   <li key={id}>
     <Link to={`${this.props.match.url}/${id}`}>{name}</Link>
   </li>
  ))}
</ul>

// Route uses props to get the matching url and accepts a dynamic id
<Route path={`${this.props.match.url}/:postId`} component={blogPost}/>
```

[Back to 🔝](#questions)

---

<a name="withRouter"></a>
### 3️⃣ Passing Props via `withRouter()`

Routes come with a robust set of information that is delivered in the form of props. For example, we can extract params we had set up or a different location to navigate to. (Prop data is stored in `location`, `match`, and `history` objects.)

Often times in our projects we have a component that is not associated with a route but could benefit from the above props. We could pop-drill the data we want, but that could get confusing and messy quickly. 

Instead, we can use the higher-order component `withRouter()` on the component that just needs quick access to the props. For example, a form that wants to `history.push()` to a location such as a confirmation screen. 

```jsx
•••
import { withRouter } from 'react-router';

const Form = () => {

  // This function uses the route props to go to a new page after handling the form submission
  const handleSubmit = (event) => {
    •••
    props.history.push(`/confirmation`)
  };

  <form onSubmit={handleSubmit}>
    •••
  </form>

}

// Higher-order component that exposes the closest route's props to the Form component
export default withRouter(Form) 
```


[Back to 🔝](#questions)


---

<a name="queryParams"></a>
### 4️⃣ Passing Data via URL Query Params

React Router lets us pass data through the URL so that it can be consumed by the linked-to component. Appending this data to the URL is called query parameters.  

####`useLocation()` & custom extraction hook
```jsx
import {
  •••
  Link,
  useLocation
} from 'react-router-dom';

// React Router suggests this custom hook to pull the value from the url
const useQuery = () => {
  return new URLSearchParams(useLocation().search);
}

// Component that has the data we want to send
const ParentComponent = () => {
 
  // Hook from above
  let query = useQuery();

  return (
    <div>
      {/* Data is added after the "?" */}
      <Link to='/account?name=netflix'>Netflix</Link>

      {/* Data is pulled out of the URL and passed as a prop to the child component  */}
      <ChildComponent name={query.get('name')} />
    </div>
  );
}

// Component receiving query params props 
const ChildComponent = ({name}) => {
  return <h1>{name}</h1>
}
```

####`useParams()` Hook
```jsx
import { useParams } from 'react-router-dom';

const Blog = () => {
  return (
    {/* Link passes in an id as params in the slug*/}
    <Link to={`${props.match.url}/${id}`} />Post Name</Link>

    {/* Route is set up to dynamically accept any id passed in the slug */}
    <Route path=`${props.match.url}/:id`>
      <BlogPost />
    </Route>
  )
}

const BlogPost = () => {

  {/* useParams pulls the id param out of the slug so it can be used */}
  let { id } = useParams();
  return <div>Now showing post {id}</div>;

}
```


[Back to 🔝](#questions)


---

<a name="activeLinks"></a>
### 5️⃣ Styling Active Links

A simple upgrade to a site's UX is to show an active style in the navigation for whatever page is showing. 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/ozthils8djc9e4x279yr.jpg)

React Router makes this simple with the `<NavLink />` component, which replaces the standard `<Link />`. 

```jsx
import { NavLink } from 'react-router-dom';

<NavLink to='/' exact>Home</NavLink>
<NavLink to='/about'>About</NavLink>
<NavLink to='/contact'>Contact</NavLink>

// Note that the "Home" link has the prop "exact". 
// This prevents it from activating unless it's clicked.
```

This new component adds an `.active` CSS class to any link that has its page shown. We can then target that generated class with any style we prefer. 

```css
.nav__link:hover, 
.nav__link:active,
.nav__link.active { <--- React Router Generated
  color: green;
}
```

If we don't want to use the class name `.active` we can even specify our own name. This just needs to be passed to the `activeClassName` prop. 

```jsx
import { NavLink } from 'react-router-dom';

<NavLink 
  to='/' 
  exact 
  activeClassName='nav__link--active' <-------
>Home</NavLink>
```

Alternatively, we could use the `activeStyle` JS styles prop to update the component directly. 
```jsx
import { NavLink } from 'react-router-dom';

<NavLink 
  to='/' 
  exact 
  activeStyle={{
    color: 'green'
  }}
>Home</NavLink>

```



[Back to 🔝](#questions)


---

##Summary

Alright, my friends, that is it for today. I hope you learned something new about React Router that will help your next project. 

If you are looking to dig deeper, check out the various resources below. Happy coding! 🤓

---

<a name="resources"></a>
###Resource Links
* [Quick Start Documentation](https://reactrouter.com/web/guides/quick-start)

* [The Net Ninja Explaining React Router](https://www.youtube.com/watch?v=QUz3k2O3ZJU)

* [React The Complete Guide - (Section 11)](https://www.udemy.com/course/react-the-complete-guide-incl-redux/)

* [Nested routes with React Router v5](https://www.youtube.com/watch?v=9z-X7UUid9Q)

* [Query Params in React Router Documentation](https://reactrouter.com/web/example/query-parameters)

---

*Thumbnail designed with [Figma](https://www.figma.com/)*