SPA Navigation with React Router

Anthony BosekAnthony Bosek
5 min read

In this blog, we'll be covering some core concepts of React Router - the standard routing library for React applications.

** A quick note on version compatibility before we start: this blog covers a mix of v5 and v6 features. The core v5 features we'll discuss - Link, NavLink, and useParams - remain fully backward compatible with v6. However, useNavigate & other features were introduced with the release of React Router v6. There is far too much to cover in this basic intro, but the documentation is excellent, you can check it out here: React Router. Now, let's get started!

SPAs and Why Routing Matters

Many React apps are built as single-page applications (SPAs). This means that instead of traditional multi-page apps that refresh with each page change, SPAs dynamically update content on a single page without refreshes.

The benefits of this approach are:

  • Faster page transitions without refreshes.

  • A cleaner app structure with component-based routing.

  • Overall smoother user experience.

You may be asking yourself, "How do we handle navigation in an SPA without page refreshes?" Well, this is where the benefits of React Router can really be seen...

React Router allows you to handle routing in a React SPA. It lets you build an app with different URL paths that display different components and data.

Some of the key features React Router provides are:

  • Declarative routing configuration using JSX components.

  • Client-side route handling without page refreshes.

  • Link components for navigation between routes.

  • Route parameter access for dynamic URLs.

In summary, React Router enables seamless routing and navigation in SPAs, without the need for page refreshes. This results in a faster, smoother user experience!

Now that we know why routing matters for SPAs, let's dive into how React Router works and maybe learn a little something along the way...

React Router provides two components for client-side route navigation:

  1. <Link>

  2. <NavLink>

These components differ from normal anchor tags in some important ways:

Anchor Tag

  • Uses the native HTML anchor tag: <a></a>.

  • Triggers a full page refresh.

  • Requires server-side configuration.

  • Results in more bloated markup.

With server-side routing, a user clicks a link that requests a new page or new data from the server (another computer). This triggers the page to refresh with the new file served up. Most often separate HTML files for each page.

Link & NavLink

  • React components that use routing info from React Router.

  • Handle routing client-side without page refreshes.

  • No server-side configuration is needed.

  • Cleaner markup focused on UI.

Code example:

// HTML Anchor tag
<a href="/users">Users</a> 

// React-Router Link Component
<Link to="/users">Users</Link>

// React-Router NavLink Component with options
<NavLink
  to="/messages"
  className={ ({ isActive, isPending }) =>
    isPending ? "pending" : isActive ? "active" : ""
  }
>
  Messages
</NavLink>;

The <Link> component provides client-side navigation without the unnecessary markup and page refresh!

A <NavLink> is a special kind of <Link> that knows whether or not it is "active" or "pending". This is useful when building a navigation menu, like a set of tabs where you'd like to show which tab is currently selected.

Both <Link> and <NavLink> are rendered as anchor tag elements, <a></a>. However, React Router 'hi-jacks' their default behavior and redirects to their internal routing structure. Sneaky React Router...

In summary:

  • Use Link/NavLink for client-side routing.

  • Avoid anchor tags and avoid page refreshes.

  • Use <Link> for general links.

  • Use <NavLink> when building navigation so you can style the active link.

React Router allows for smooth navigation throughout your SPA!

Accessing Route Parameters with useParams( )

The useParams hook allows you to access dynamic segments of the URL within your components.

Code example:

// React Element
<Route path="/users/:userId"/>
// URL string
"https://mysite.com/users/0456023"

We could access that :userId param with useParams:

import { useParams } from 'react-router-dom';

function UserPage() {
  const { userId } = useParams();

  return <p>User ID: {userId}</p>;
} // userId = 0456023 from example above

A more complex code example:

<Route path="/users/:userId/posts/:postId">
// URL string
"https://mysite.com/users/0456023/posts/102"

The useParams hook would return an object like:

{
  userId: '0456023', 
  postId: '102' 
}

It contains all the route parameters mapped to the key names. The keys in the useParams object match the names of the dynamic segments in the route path.

Other code examples of what you could be accessed:

// Route: /users/:userId/books/:bookId
{userId, bookId} 

// Route: /articles/:category/:articleId
{category, articleId}

The key things to note here are:

  • useParams returns an object.

  • The keys are the dynamic parameter names.

  • The values are strings of the parameter values delineated by : in the URL string.

So in summary, useParams gives you an object with all of the route's dynamic parameters ready for you to use in your components. Pretty snazzy, and effective too!

Programmatic Navigation with useNavigate( )

In addition to declaring routes and links, you may need to navigate programmatically in response to some user interaction. For example, you may want to navigate after a form is submitted or a button is clicked.

This is where the useNavigate hook comes in handy!

import { useNavigate } from 'react-router-dom';

function ProfilePage() {

  const navigate = useNavigate();

  function handleSave() {
    // Save profile data

    navigate('/dashboard'); // Navigate to dashboard
  }

  return (
    <button onClick={handleSave}>Save Profile</button>
  );

}

useNavigate returns a function that lets you navigate to a new route programmatically. You can also pass a second 'options' argument which may include state values and other valuable info!

Some use cases:

  • Navigating after form submission.

  • Taking users to a "success" page after an action.

  • General redirection based on application logic.

Both useParams and useNavigate are custom hooks that must follow the same basic principles as all hooks in React:

  • Hooks can only be called inside React function components.

  • Hooks can only be called at the top level of a component.

  • Hooks cannot be conditional and must begin with 'use'.

There you have it - we covered just a bit of the basics of React Router - a few of its key hooks and components for routing, navigation, and params. I hope this intro provided a nice overview of React Router concepts to get you started! This was a generalized glimpse into the realm of React Router, there is so much more you can do! Dive deep... as always, Happy Hacking <> { } </> !!

0
Subscribe to my newsletter

Read articles from Anthony Bosek directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Anthony Bosek
Anthony Bosek

Southern California ๐ŸŒŠ native, currently reside in sunny Phoenix, Arizona ๐ŸŒต. I am a Software Engineer and Full Stack Developer with a passion for clean code, efficient logic, and that oh so sweet 'syntactic sugar'!! Graduate of Flatiron School always seeking greater understanding in the minutia of software engineering. ๐Ÿ’ปMy tech stack includes Python, Flask, SQL, React, JS, D3, and more. I am an avid Premier League enthusiast โšฝ and lover of life!!