React Router DOM helps you create a Single-Page Application (SPA) where the user can navigate between different components without reloading the page.
Installation
Install React Router DOM using npm:
npm install react-router-dom
BrowserRouter
Wrap your entire app inside BrowserRouter
so that the React Router DOM knows how to handle different routes in your app.
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import App from './App.jsx'
import "./index.css";
import {
RouterProvider,
createBrowserRouter,
createRoutesFromElements,
Route,
} from "react-router-dom";
createRoot(document.getElementById('root')).render(
<StrictMode>
<RouterProvider router={router}/> //router here will be defined in the next step.
</StrictMode>
)
Here, we are in the main.jsx which is index file for the react application created by using Vite.
Routes and Route
Routes
holds all your routes, and each Route
points to a specific component. Route
can be nested.
-
path
: the URL that users will visit. -
element
: the component that should be displayed when that URL is visited.
There are two ways to define routes here:
//use plain objects
const router = createBrowserRouter([
{
path: '/',
element: <App />,
children: [
{
path: '',
element: <Home />
},
{
path: 'about',
element: <About/>
},
{
path: 'contact',
element: <Contact/>
},
]
},
])
In this section, we define various routes and the corresponding components that will be displayed for each specific path. For instance, the component <About/>
will be rendered when navigating to example.com/about.
Outlet and Nested Routes
When you want to display nested components (like a parent-child structure), you can use Outlet
. This allows for nested routes.
In certain web applications, it is necessary to consistently display the same header and footer; to achieve this, we utilize the <Outlet/>
tag within App.jsx
, establishing it as the primary layout. Alternatively, some developers opt for <layout/>
components to fulfill a similar function.
Parent Component:
import { useState } from 'react'
import './App.css'
import { Footer, Header} from './components';
import {Outlet} from "react-router-dom";
export default function App() {
return (
<>
<Header/>
<Outlet/>
<Footer/>
</>
);
}
Second way to define routes:
This is written in the file – main.jsx
and it is also Defining Child Routes
//Configure nested routes with JSX
const router = createBrowserRouter(
createRoutesFromElements(
<Route path="https://dev.to/" element={<App />}>
<Route path='' element={<Home />} />
<Route path='about' element={<About/>}>
<Route path='later' element={<Later/>} />
</Route>
<Route path='contact' element={<Contact/>} />
<Route path='user/:id' element={<User/>} />
<Route path='github' element={<Github/>} />
</Route>
)
)
This represents the second and preferred method for defining routes. In this instance, we are nesting routes within the /About path.
When users visit /about/later
, the About
component will be displayed with Later
inside it.
Link Tag
The Link
component helps you navigate between pages without refreshing. It’s like an anchor (<a>
) tag but works in an SPA.
import React from 'react'
import { Link,} from "react-router-dom";
export default function Footer() {
return (
<section>
<ul>
<li>
<Link
to={"/about"}
>
About
</Link>
</li>
<li>
<Link
to={"./contact"}
>
Contact Us
</Link>
</li>
</ul>
</section>
);
}
NavLink Tag and Active Links
The NavLink component is used to create navigation links that can automatically apply specific styles or classes to the link that matches the current URL (active link).
It uses a className prop, which can be a function to dynamically apply classes.
import React from 'react'
import { NavLink } from "react-router-dom";
export default function Header() {
return (
<nav>
<ul>
<li>
<NavLink
to="https://dev.to/"
className={({ isActive }) =>
`text-sm font-semibold ${
isActive ? "text-orange-500" : "text-gray-800"
} hover:text-gray-900`
}
>
Home
</NavLink>
</li>
<li>
<NavLink
to="https://dev.to/about"
className={({ isActive }) =>
`text-sm font-semibold ${
isActive ? "text-orange-500" : "text-gray-800"
} hover:text-gray-900`
}
>
About
</NavLink>
</li>
<li>
<NavLink
to="https://dev.to/contact"
className={({ isActive }) =>
`text-sm font-semibold ${
isActive ? "text-orange-500" : "text-gray-800"
} hover:text-gray-900`
}
>
Contact
</NavLink>
</li>
</ul>
</nav>
);
}
useParams and Dynamic Segments
In React Router DOM, the useParams hook allows you to access URL parameters from the current route. It is commonly used when you have dynamic routes and need to extract the values from the URL to display specific information or perform certain actions.
First, we need to declare dynamic routes in the main router.
<Route path='user/:id/post/:postid' element={<User/>} />
Then we use useParams
hook in the route component.
import React from 'react'
import { useParams } from "react-router-dom";
export default function User() {
const {id, postid} = useParams();
return (
<div>User: {id}, Post: {postid}
</div>
)
}
Data Loading
Fetch data from the GitHub API: It retrieves the profile information for the user when the component mounts. The fetched data is stored in the data state variable. The component then displays the number of followers (data.followers) and the user’s avatar image (data.avatar_url). If the data fetch fails, the error is logged, and the failed data is stored in the state.
import React,{useState, useEffect} from 'react'
export default function Github() {
const [data, setData] = useState([]);
useEffect(() => {
fetch("https://api.github.com/users/your_user_name")
.then((response) => response.json())
.then((json) => setData(json))
.catch((data) => {console.log(data)
setData(data)});
}, []);
return (
<div>
<h1>Github Followers: {data.followers} </h1>
<img src={data.avatar_url} alt="avatar" width="200" />
</div>
);
}
Now in React Router DOM v6.4+, you can use loaders to fetch data before rendering a component. Loaders are a part of the new data-fetching capabilities in React Router, allowing you to load data asynchronously before a route renders, rather than fetching it within useEffect inside the component. This improves data loading efficiency and prevents rendering before the data is ready.
- In the route configuration, you define a loader function that will fetch the data. This data is then passed to the component through the useLoaderData hook.
<Route loader={githubInfoLoader} path="github" element={<Github />} />
- Instead of using
useEffect
anduseState
, you useuseLoaderData
to access the data fetched by the loader.
import React from 'react'
import { useLoaderData } from "react-router-dom";
export default function GithubLoader() {
const data = useLoaderData();
return (
<div>
<h1>Github Followers: {data.followers} </h1>
<img src={data.avatar_url} alt="avatar" width="200" />
</div>
);
}
githubinfo.js
export const githubLoaderInfo = async () => {
const response = await fetch("https://api.github.com/users/username");
return response.json();
}
We can declare the upper function in the component also but it is not considered a good practice.
Source link
lol