Router - anastasiamexa/react-complete-guide-course-resources GitHub Wiki
React Router is a popular library for managing routing in React applications. It allows developers to create single-page applications with multiple views, each represented by its own URL. React Router is commonly used with React applications, and react-router-dom is a package within React Router that provides DOM bindings for React Router, enabling routing in web applications.
First, you need to install react-router-dom in your project:
npm install react-router-dom
For complete setup and installation guide use the official documentation.
1. Adding a Router:
First thing to do is create a Browser Router and configure our first route. This will enable client side routing for our web app.
import { RouterProvider, createBrowserRouter } from "react-router-dom";
createBrowserRouter
is used to create a custom router instance.
Routes are defined in an array. Each route object contains:
- path: the URL path for the route.
- element: the component to render when the path matches.
- children: nested routes relative to the parent route.
const router = createBrowserRouter([
{
path: "/",
element: <RootLayout />,
children: [
{ index: true, element: <HomePage /> },
{
path: "events",
element: <EventsRootLayout />,
children: [
{ index: true, element: <EventsPage /> },
{ path: ":id", element: <EventDetailPage /> },
{ path: "new", element: <NewEventPage /> },
{ path: ":id/edit", element: <EditEventPage /> },
],
},
],
},
]);
2. Using the Router:
In the App
component that serves as the root component of the application, we add the RouterProvider
which is provided by React Router to supply the router instance to the entire application.
function App() {
return <RouterProvider router={router} />;
}
3. Redirecting:
Link
is a component provided by react-router-dom for declarative navigation around the application. It renders an anchor tag (<a>
) with a specified destination to prop.
Example:
import { Link } from 'react-router-dom';
function MyComponent() {
return (
<div>
<Link to="/about">About</Link>
</div>
);
}
NavLink
is similar to Link
, but it adds styling attributes when its to prop matches the current URL. This is useful for styling navigation links based on whether they're currently active.
Example:
import { NavLink } from 'react-router-dom';
function Navigation() {
return (
<nav>
<NavLink to="/about" className={({ isActive }) =>isActive ? classes.active : undefined}>About</NavLink>
<NavLink to="/contact" className={({ isActive }) =>isActive ? classes.active : undefined}>Contact</NavLink>
</nav>
);
}
4. Passing params:
useParams
is a hook provided by react-router-dom for accessing parameters in the URL. It returns an object containing key-value pairs of the URL parameters.
Example:
import { useParams } from 'react-router-dom';
function UserProfile() {
const params = useParams();
return <h1>User Profile: {params.username}</h1>;
}
5. Handling Not Found Errors:
Anytime your app throws an error while rendering, loading data, or performing data mutations, React Router will catch it and render an error screen. Let's make our own error page. Example:
import { useRouteError } from "react-router-dom";
export default function ErrorPage() {
const error = useRouteError();
console.error(error);
return (
<div id="error-page">
<h1>Oops!</h1>
<p>Sorry, an unexpected error has occurred.</p>
<p>
<i>{error.statusText || error.message}</i>
</p>
</div>
);
}
Set the <ErrorPage>
as the errorElement
on the root route.
import ErrorPage from "./error-page";
const router = createBrowserRouter([
{
path: "/",
element: <RootLayout />,
errorElement: <ErrorPage />,
children: [
{ index: true, element: <HomePage /> },
{
path: "events",
element: <EventsRootLayout />,
children: [
{ index: true, element: <EventsPage /> },
{ path: ":id", element: <EventDetailPage /> },
{ path: "new", element: <NewEventPage /> },
{ path: ":id/edit", element: <EditEventPage /> },
],
},
],
},
]);
React Router simplifies routing in React applications by providing a declarative and intuitive way to manage navigation and views. With components like <Link>
, <NavLink>
, and hooks like useParams
, you can create dynamic and flexible routing systems in your applications. Additionally, features like relative paths and nested layout routes allow for better organization and scalability in larger projects.
In React Router v6, routes can have a loader
function associated with them. This function is invoked when the route is matched, allowing you to perform asynchronous tasks such as fetching data before rendering the route's component. This is particularly useful in scenarios where you need to fetch data from an API or perform other asynchronous operations before rendering the component.
The loader
function should return a Promise that resolves to the data needed by the component. Once the Promise is resolved, the component associated with the route is rendered with the fetched data.
Here's an example of how you can define a route with a loader function:
const router = createBrowserRouter([
{
path: "events",
element: <EventsRootLayout />,
children: [
{
index: true,
element: <EventsPage />,
loader: eventsLoader,
},
{
path: ":id",
id: 'event-detail',
loader: eventDetailLoader,
children: [
{ index: true, element: <EventDetailPage /> },
{ path: "edit", element: <EditEventPage /> },
],
},
{ path: "new", element: <NewEventPage /> },
],
},
Overall, this configuration sets up the routes for managing events in your application, including listing events, viewing event details, editing events, and creating new events. It demonstrates how to nest routes and use dynamic segments in paths, as well as how to associate loader functions with specific routes for data loading.
In React Router v6, both useLoaderData()
and useRouteLoaderData()
are hooks provided by the library to access data fetched by the loader function in route components. However, they have slightly different use cases and behaviors:
1. useLoaderData():
-
useLoaderData()
is a hook provided by React Router v6 to access the data fetched by the loader function directly within the route component where it's used. - This hook is typically used within the route component that corresponds to the route with the loader function.
- It returns the data fetched by the loader function for the current route.
import { useLoaderData } from 'react-router-dom';
function MyComponent() {
const data = useLoaderData();
// Use the fetched data here
}
2. useRouteLoaderData():
-
useRouteLoaderData()
is a hook provided by React Router v6 to access the data fetched by the loader function from any component within the route hierarchy. - This hook can be used in nested components within the route hierarchy to access the data fetched by the loader function of the parent route.
- It traverses the route hierarchy upwards to find the nearest parent route with a loader function and returns its data.
import { useRouteLoaderData } from 'react-router-dom';
function MyNestedComponent() {
const data = useRouteLoaderData();
// Use the fetched data from the nearest parent route's loader function
}
In summary, useLoaderData()
is used within the route component itself to directly access the data fetched by the loader function for that specific route, while useRouteLoaderData()
is used in nested components within the route hierarchy to access the data fetched by the loader function of the nearest parent route. Choose the appropriate hook based on whether you need to access the data directly within the route component or within nested components.
In React Router v6, the action
property in a route object allows you to specify a function to be executed when the route is matched. This function can perform certain actions before rendering the component associated with the route. Let's break down how it works:
- In route object when the URL matches this path, the associated component will be rendered.
- Additionally, the action property is defined with a function.
{
path: "new",
element: <NewEventPage />,
action: newEventAction
}
The newEventAction
function is defined elsewhere in your codebase and is associated with the route.
function newEventAction() {
// Perform actions before rendering NewEventPage
// This function can execute any necessary logic, such as fetching data or updating state
}
- The
newEventAction
function is invoked when the route is matched. - It can perform any necessary actions before rendering the associated component, such as fetching data from an API, updating local state, or executing other logic.
- Once the action is completed, the associated component (
<NewEventPage />
) will be rendered.
The action function allows you to execute custom logic before rendering a component, which can be useful for scenarios where you need to perform certain tasks before displaying content to the user. This might include data fetching, authentication checks, or any other initialization logic.
In summary, the action property in a route object allows you to define a function to be executed before rendering the associated component. This provides a way to perform custom actions or initialization logic specific to a particular route in your application.