Lesson 5

Navigating Single-Page Applications with React Router

Introduction and Lesson Plan

Hey there, coding enthusiasts! Today, we're delving into the exciting world of single-page applications (SPAs), with a key focus on navigation. If you're wondering what an SPA is, think of Facebook. When you navigate from your news feed to your profile or to your messages, the entire page doesn't refresh, only certain parts do. Traditional browser navigation doesn't quite apply here. That's when we whip out our secret weapon: the React Router, the Narnia's wardrobe of SPAs.

Route Creation and Usage

Inside every React Router app, there's a key BrowserRouter component. This key component essentially keeps the user interface in sync with the URL on the browser.

Routes are managed using a Routes component that contains Route components for each path in our application. The Route component matches the current location with its path prop and generates the corresponding UI. For instance, the root of the app renders the HomePage and "/about" renders the AboutPage.

1import { BrowserRouter as Router, Routes, Route } from 'react-router-dom'; 2import HomePage from './HomePage'; 3import AboutPage from './AboutPage'; 4 5function AppRouter() { 6 return ( 7 <Router> 8 <Routes> 9 <Route path="/" element={<HomePage />}/> 10 <Route path="/about" element={<AboutPage />} /> 11 </Routes> 12 </Router> 13 ); 14} 15 16export default AppRouter;

When we write BrowserRouter as Router, we're essentially saying, "import the BrowserRouter component from the React Router library and refer to it as Router in our code". It's just renaming BrowserRouter to Router.

Linking Between Pages

Navigation between routes is akin to teleportation, made possible using the Link component. Rather than enduring clunky page refreshes, Link smoothly alters the URL by manipulating the browser history, a superpower we indeed need for SPAs!

1import { BrowserRouter as Router, Routes, Route, Link } from 'react-router-dom'; 2import HomePage from './HomePage'; 3import AboutPage from './AboutPage'; 4 5function AppRouter() { 6 return ( 7 <Router> 8 <nav> 9 <ul> 10 <li><Link to="/">Home</Link></li> 11 <li><Link to="/about">About</Link></li> 12 </ul> 13 </nav> 14 <Routes> 15 <Route path="/" element={<HomePage />} /> 16 <Route path="/about" element={<AboutPage />} /> 17 </Routes> 18 </Router> 19 ); 20} 21 22export default AppRouter;

The <nav> tag in HTML is used to define a section of a web page that contains navigation links. Here we define two links using the Link component from React Router, which allow us to navigate between the Home and About pages of our web application.

When a user clicks <Link to="/">Home</Link>, React searches the Routes for one with path="/" . <Route path="/" element={<HomePage />} /> matches the path, so React renders the <HomePage> component.

Handling Dynamic Routes

Web applications often showcase dynamic pages like /users/:id, where id is a variable part of the URL. This part changes based on the individual user. React Router steps in here, too. We use id for such dynamic routes in the path prop of Route!

1<Route path="/users/:id" element={<UserPage />} />

Now, within the UserPage component, we can easily access the id parameter using useParams hook.

1import { useParams } from 'react-router-dom'; 2 3function UserPage() { 4 let { id } = useParams(); 5 return <p>User ID: {id}</p>; 6}
Nested Routes

Yes, we have another layer of routing. These are the so-called nested routes, which are essentially routes within other routes. They come in handy when we need to display data based on specific conditions in one section of our web page while keeping the rest of it unchanged.

For example, on Github, when you navigate to a particular repository, you'll see tabs like Pull Requests, Actions, Projects, etc. Each of these tabs represents different views or routes, but they are nested within the same repository.

To create nested routes in React Router, you just nest Route components:

1import { BrowserRouter as Router, Routes, Route } from 'react-router-dom'; 2import UserPage from './UserPage'; 3import UserProfile from './UserProfile'; 4import UserPosts from './UserPosts'; 5 6function AppRouter() { 7 return ( 8 <Router> 9 <Routes> 10 <Route path="/users/:id/*" element={<UserPage />}> 11 <Route path="profile" element={<UserProfile />} /> 12 <Route path="posts" element={<UserPosts />} /> 13 </Route> 14 </Routes> 15 </Router> 16 ); 17} 18 19export default AppRouter;

When creating nested routes, the parent route component (in our case UserPage) should include an Outlet where the child routes (UserProfile and UserPosts) will render based on the current URL.

Here's an example of how you might implement this in UserPage:

1import { Outlet } from 'react-router-dom'; 2 3function UserPage() { 4 return ( 5 <div> 6 <h2>User Page</h2> 7 {/* Other common elements like a header or navigation menu can go here */} 8 <Outlet /> 9 {/* Outlet is where UserProfile or UserPosts will render */} 10 </div> 11 ); 12}

In this UserPage component, the <Outlet /> is where either the UserProfile or UserPosts will render based on the current path. If the current path is users/1/profile, UserProfile will render at the Outlet's location. If it's users/1/posts, UserPosts will render instead. Other elements in UserPage outside <Outlet /> will remain unchanged, allowing the reuse of common elements across different views.

Lesson Summary and Practice

Congratulations on navigating through the winding roads of SPAs so skillfully! We've unearthed the magic of React Router, setting it up, creating and using routes, linking different parts of our app, and adding dynamic and nested URLs.

Now, brace yourselves for practice exercises that provide an exciting, hands-on experience of these newly-acquired concepts. Remember, the more you practice, the better you get! Are you ready to test your mettle with React Router? Let's move on to the exercises!

Enjoy this lesson? Now it's time to practice with Cosmo!

Practice is how you turn knowledge into actual skills.