Back to articles

Beyond React Router: Advanced Client-Side Routing Strategies

AuthorMajd Muhtaseb04/28/20257 minutes
Beyond React Router: Advanced Client-Side Routing Strategies

Introduction

React Router is a staple for handling navigation in React applications. However, as your application grows, you might need more advanced techniques to optimize performance and enhance user experience. This article delves into strategies that go beyond basic route definition and navigation.

Code Splitting with React.lazy and Suspense

One common performance bottleneck is loading the entire application bundle upfront. Code splitting allows you to load parts of your application on demand. React's React.lazy and Suspense are excellent tools for achieving this.

import React, { lazy, Suspense } from 'react';

const Home = lazy(() => import('./pages/Home'));
const About = lazy(() => import('./pages/About'));

function App() {
  return (
    <Suspense fallback={<div>Loading...</div>}>
      {/* Your Router Setup Here */}
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/about" element={<About />} />
      </Routes>
    </Suspense>
  );
}

This example demonstrates how to dynamically import components, loading them only when the route is accessed. Suspense provides a fallback UI while the component is loading.

Data Fetching on Route Change

Fetching data before rendering a component is crucial for many applications. While you can perform data fetching within the component itself, doing it before the component mounts can lead to a smoother user experience. Libraries like react-router-dom provide hooks like useLoaderData to achieve this using the newer createBrowserRouter approach.

import { createBrowserRouter, RouterProvider, useLoaderData } from "react-router-dom";

async function getUserData() {
  const response = await fetch("https://api.example.com/user");
  return response.json();
}

function UserProfile() {
  const user = useLoaderData();

  return (
    <div>
      <h1>{user.name}</h1>
      <p>{user.email}</p>
    </div>
  );
}

const router = createBrowserRouter([
  {
    path: "/user",
    element: <UserProfile />,
    loader: getUserData,
  },
]);

function App() {
  return <RouterProvider router={router} />;
}

Scroll Restoration

A frustrating user experience can arise when navigating between routes and the page doesn't remember its scroll position. React Router provides a <ScrollRestoration> component to handle this automatically.

import { ScrollRestoration } from "react-router-dom";

function App() {
  return (
    <>
      {/* Your Router Setup Here */}
      <ScrollRestoration />
      <Routes>
        {/* ... Routes ... */}
      </Routes>
    </>
  );
}

Conclusion

Mastering advanced routing techniques is essential for building performant and user-friendly React applications. Code splitting, pre-fetching data, and scroll restoration are just a few strategies to consider as your application scales. Experiment with these techniques to find the best approach for your specific needs.