Seamless Client-Side Routing in React Applications with React Router
Written on
Client-Side Routing with React Router
When it comes to creating multi-page applications in React, incorporating React Router is essential. Renowned for its effectiveness and simplicity, React Router is a favored tool for managing client-side routing in React projects.
In this guide, we will walk through the straightforward steps to integrate React Router for seamless routing functionalities in your applications.
Installing Dependencies
To set up React Router, you can follow this quick tutorial. First, ensure you install the necessary packages:
npm install react-router-dom @types/react-router-dom
Creating a Fake API
For demonstration purposes, we will utilize a mock API that delays data retrieval by one second. This setup allows us to illustrate the use of loaders during data fetching. The first function retrieves all todo items, while the second fetches a specific todo based on its ID.
export type Todo = {
id: number;
label: string;
};
const todos: Todo[] = [
{
id: 1,
label: "Walk a dog",
},
{
id: 2,
label: "Shopping",
},
];
function wait(time: number) {
return new Promise((resolve) => {
setTimeout(() => {
resolve("ok");}, time);
});
}
export async function loadTodos() {
await wait(1000);
return todos;
}
export async function getTodo(id: string) {
await wait(1000);
return todos.find(todo => todo.id.toString() === id) || null;
}
Creating Components
Home Component
export default function Home() {
return <h1>Homepage</h1>;
}
Not Found Component
export default function NotFound() {
return <h1>Not Found</h1>;
}
Using Loaders with React Router
With the useLoaderData hook, we can fetch data seamlessly without manual loading in components. This hook automatically revalidates data, ensuring the latest results are presented without re-fetching unnecessarily.
Todos Component
import { Link, useLoaderData } from "react-router-dom";
import { Todo } from "../api/todos.ts";
export default function Todos() {
const todos: Todo[] = useLoaderData();
return (
<div>
<h1>Todos</h1>
{todos.map(todo => (
<div key={todo.id}>
<Link to={/todo/${todo.id}}>{todo.label}</Link></div>
))}
</div>
);
}
Todo Detail Component
import { useLoaderData, useParams } from "react-router-dom";
import { Todo } from "../api/todos.ts";
export default function TodosDetail() {
const todo: Todo = useLoaderData();
return (
<div>
<h1>Todo Detail</h1>
<p>Id: {todo.id}</p>
<p>Label: {todo.label}</p>
</div>
);
}
Setting Up the App Component
In App.tsx, we will define the navigation structure that appears across different routes. The useNavigation hook along with navigation.state allows us to indicate loading status during page transitions.
import {
createBrowserRouter,
createRoutesFromElements,
Route,
Outlet,
Link,
RouterProvider,
useNavigation
} from "react-router-dom";
import Home from "./components/Home.tsx";
import Todos from "./components/Todos.tsx";
import NotFound from "./components/NotFound.tsx";
import TodosDetail from "./components/TodoDetail.tsx";
import { getTodo, loadTodos } from "./api/todos.ts";
const Layout = () => {
const navigation = useNavigation();
if (navigation.state === "loading") {
return <h1>Loading...</h1>;}
return (
<nav>
<Link to="/">Home</Link>
<Link to="/todos">Todos</Link>
</nav>
);
};
function App() {
const router = createBrowserRouter(
createRoutesFromElements(
<Route element={<Layout />}>
<Route index element={<Home />} />
<Route path="todos" element={<Todos />} loader={loadTodos} />
<Route path="todo/:id" element={<TodosDetail />} loader={({ params }) => getTodo(params.id)} />
<Route path="*" element={<NotFound />} />
</Route>
)
);
return <RouterProvider router={router} />;
}
export default App;
Running the Application
To run your application, execute:
npm run dev
You should see the homepage initially. When you click on the Todos link and select a specific todo, you will notice a loading state while transitioning between routes. If you enter an invalid URL, a Not Found page will be displayed.
Conclusion
In just a few steps, we have successfully implemented multiple routes with loaders and enhanced the user experience by introducing loading states. Additionally, we handled invalid routes with a Not Found page.
For further insights on database interactions using Drizzle, stay tuned for our upcoming tutorial!
Stackademic 🎓
Thank you for sticking with us! Please consider applauding and following the writer! đź‘Ź Connect with us on X | LinkedIn | YouTube | Discord. Explore more content at Stackademic.com.
The first video title is React Router Tutorial - Setup in 5 Minutes - YouTube. This video provides a quick setup guide for React Router in your applications.
The second video title is Client-side routing with react-router@3 (Part 1) - YouTube. This video dives into client-side routing using React Router, offering practical insights and examples.