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.
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
.
JavaScript1import { 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
.
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!
JavaScript1import { 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.
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
!
JavaScript1<Route path="/users/:id" element={<UserPage />} />
Now, within the UserPage
component, we can easily access the id
parameter using useParams
hook.
JavaScript1import { useParams } from 'react-router-dom'; 2 3function UserPage() { 4 let { id } = useParams(); 5 return <p>User ID: {id}</p>; 6}
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:
JavaScript1import { 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
:
JavaScript1import { 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.
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!