Learning React Router
In this article, we will explore React Router and create a webpage that can navigate to different sections. We will create a components
folder with subfolders for about
, contact
, footer
, header
, and home
.
The Footer
and Header
components will remain constant, while the content of other components will change based on user interaction.
An interesting functionality of react-router-dom
is Link
and NavLink
. The Link
component can be used instead of the anchor
tag to prevent the entire page from refreshing. The NavLink
component provides additional features.
<NavLink
to="/"
className={({ isActive }) =>
`block py-2 pr-4 pl-3 duration-200 ${
isActive ? "text-orange-700" : "text-gray-700"
} border-b border-gray-100 hover:bg-gray-50 lg:hover:bg-transparent lg:border-0 hover:text-orange-700 lg:p-0`
}
>
Home
</NavLink>
Notice that in NavLink
, the className
is defined inside a callback because it provides an isActive
variable. The isActive
variable synchronizes with the URL to determine if a particular page is active, allowing us to apply different styles accordingly.
Setting Up Layout with React Router
Since we want the header and footer to remain constant while the rest of the content changes based on user actions, we will utilize the Outlet
component from React Router.
import React from 'react'
import { Outlet } from 'react-router-dom'
import Header from './components/Header/Header'
import Footer from './components/Footer/Footer'
function Layout() {
return (
<>
<Header />
<Outlet />
<Footer />
</>
)
}
export default Layout
The Outlet
component will render the child route components, while the header and footer remain the same.
Defining Routes
We will define the routes in the main.js
file:
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.jsx'
import './index.css'
import { createBrowserRouter, RouterProvider } from 'react-router-dom'
import Layout from './Layout.jsx'
import Home from './components/Home/Home.jsx'
import About from './components/About/About.jsx'
import Contact from './components/Contact/Contact.jsx'
const router = createBrowserRouter([
{
path: '/',
element: <Layout />,
children: [
{
path: '', // this matches the root path
element: <Home />
},
{
path: 'about',
element: <About />
},
{
path: 'contact',
element: <Contact />
}
]
}
])
ReactDOM.createRoot(document.getElementById('root')).render(
<React.StrictMode>
<RouterProvider router={router} />
</React.StrictMode>
)
When the URL is /about
, the About
component will be rendered in place of the Outlet
.
Alternate Route Definition Syntax
There is an alternate, simpler syntax for defining routes:
const router = createBrowserRouter(
createRoutesFromElements(
<Route path='/' element={<Layout />}>
<Route path='' element={<Home />} />
<Route path='about' element={<About />} />
<Route path='contact' element={<Contact />} />
</Route>
)
)
Dynamic Routes
For scenarios like user-specific data on social media platforms, we can create dynamic routes:
const router = createBrowserRouter(
createRoutesFromElements(
<Route path='/' element={<Layout />}>
<Route path='' element={<Home />} />
<Route path='about' element={<About />} />
<Route path='contact' element={<Contact />} />
<Route path='user/:userid' element={<User />} />
</Route>
)
)
In the User
component, we can access the dynamic userid
parameter using useParams
:
import React from 'react'
import { useParams } from 'react-router-dom'
function User() {
const { userid } = useParams() // useParams retrieves the id from the URL
return <div>User: {userid}</div>
}
export default User
Creating a GitHub Page
We can create another route for a GitHub page that shows the profile picture and followers count:
const router = createBrowserRouter(
createRoutesFromElements(
<Route path='/' element={<Layout />}>
<Route path='' element={<Home />} />
<Route path='about' element={<About />} />
<Route path='contact' element={<Contact />} />
<Route path='user/:userid' element={<User />} />
<Route path='github' element={<Github />} />
</Route>
)
)
The Github
component fetches data from the GitHub API:
import React, { useEffect, useState } from 'react'
function Github() {
const [data, setData] = useState([])
useEffect(() => {
fetch("https://api.github.com/users/rutripathi96")
.then(res => res.json())
.then(data => {
setData(data)
})
}, [])
return (
<div className='text-center m-4 bg-gray-600 text-white p-4 text-3'>
GitHub followers: {data.followers}
<img src={data.avatar_url} alt="GitHub profile" />
</div>
)
}
export default Github
We use useEffect
to make the API call and useState
to store the data received.
Using Loaders in React Router
To optimize the process of making API calls, we can use the loader
feature in React Router:
const router = createBrowserRouter(
createRoutesFromElements(
<Route path='/' element={<Layout />}>
<Route path='' element={<Home />} />
<Route path='about' element={<About />} />
<Route path='contact' element={<Contact />} />
<Route path='user/:userid' element={<User />} />
<Route
path='github'
element={<Github />}
loader={githubInfoLoader}
/>
</Route>
)
)
In the Github
component, use the useLoaderData
hook to access the data:
import React from 'react'
import { useLoaderData } from 'react-router-dom'
function Github() {
const data = useLoaderData()
return (
<div className='text-center m-4 bg-gray-600 text-white p-4 text-3'>
GitHub followers: {data.followers}
<img src={data.avatar_url} alt="GitHub profile" />
</div>
)
}
export default Github
export const githubInfoLoader = async () => {
const response = await fetch('https://api.github.com/users/hiteshchoudhary')
return response.json() // returns a promise
}
The useLoaderData
hook is used to retrieve the data from the githubInfoLoader
function, which fetches the GitHub user data when the cursor hovers over the NavLink
, improving the efficiency and user experience.
Usefulness of Loaders in React Router
The loader
feature in React Router optimizes the process of making API calls. Instead of waiting for the user to click a link to fetch the data, the loader initiates the API call as soon as the user hovers over the NavLink
. This pre-fetching of data ensures that the required information is ready by the time the user navigates to the page, resulting in a smoother and more efficient user experience.
Subscribe to my newsletter
Read articles from Rudraksh Tripathi directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by