React Router Basics

React Router Basics

React Router is the standard routing library for React applications. It allows you to build single-page applications with navigation between different views or pages. This tutorial covers the fundamentals of React Router, including setup, basic routing, and common patterns.

What is React Router?

React Router enables navigation between different components in a React app, updating the browser URL and rendering the appropriate component. It’s essential for building modern single-page applications (SPAs) where you want multiple “pages” without full page reloads.

Installation

First, install React Router in your project:

npm install react-router-dom

For React Router to work properly, you need to wrap your app with a Router component. The most common is BrowserRouter.

Basic Setup

import React from 'react';
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';

function App() {
  return (
    <Router>
      <div className="App">
        <Routes>
          <Route path="/" element={<Home />} />
          <Route path="/about" element={<About />} />
          <Route path="/contact" element={<Contact />} />
        </Routes>
      </div>
    </Router>
  );
}

Core Components

Routes and Route

The Routes component contains all your Route components. Each Route has a path prop (the URL path) and an element prop (the component to render).

import { Routes, Route } from 'react-router-dom';

function App() {
  return (
    <Routes>
      <Route path="/" element={<Home />} />
      <Route path="/users" element={<Users />} />
      <Route path="/users/:id" element={<User />} />
    </Routes>
  );
}

Link Component

Use Link instead of <a> tags for navigation within your React app. It prevents full page reloads.

import { Link } from 'react-router-dom';

function Navigation() {
  return (
    <nav>
      <Link to="/">Home</Link>
      <Link to="/about">About</Link>
      <Link to="/contact">Contact</Link>
    </nav>
  );
}

NavLink Component

NavLink is similar to Link but allows styling of active links.

import { NavLink } from 'react-router-dom';

function Navigation() {
  return (
    <nav>
      <NavLink to="/" className={({ isActive }) => isActive ? "active" : ""}>
        Home
      </NavLink>
      <NavLink to="/about" className={({ isActive }) => isActive ? "active" : ""}>
        About
      </NavLink>
    </nav>
  );
}

Dynamic Routing

Use URL parameters to create dynamic routes. Access them with the useParams hook.

import { useParams } from 'react-router-dom';

function User() {
  const { id } = useParams();
  
  return (
    <div>
      <h1>User ID: {id}</h1>
    </div>
  );
}

In your routes:

<Route path="/users/:id" element={<User />} />

Nested Routes

Create nested routes for more complex layouts.

function App() {
  return (
    <Routes>
      <Route path="/" element={<Layout />}>
        <Route index element={<Home />} />
        <Route path="about" element={<About />} />
        <Route path="dashboard" element={<Dashboard />} />
      </Route>
    </Routes>
  );
}

function Layout() {
  return (
    <div>
      <nav>
        <Link to="/">Home</Link>
        <Link to="/about">About</Link>
      </nav>
      <main>
        <Outlet /> {/* This renders the nested route */}
      </main>
    </div>
  );
}

Programmatic Navigation

Use the useNavigate hook to navigate programmatically.

import { useNavigate } from 'react-router-dom';

function Login() {
  const navigate = useNavigate();

  const handleLogin = () => {
    // Login logic here
    navigate('/dashboard');
  };

  return (
    <div>
      <button onClick={handleLogin}>Login</button>
    </div>
  );
}

Route Guards and Protected Routes

Create protected routes that require authentication.

function ProtectedRoute({ children }) {
  const isAuthenticated = checkAuthStatus(); // Your auth check
  const navigate = useNavigate();

  useEffect(() => {
    if (!isAuthenticated) {
      navigate('/login');
    }
  }, [isAuthenticated, navigate]);

  return isAuthenticated ? children : null;
}

// Usage
<Route path="/admin" element={
  <ProtectedRoute>
    <AdminPanel />
  </ProtectedRoute>
} />

404 Pages

Handle unmatched routes with a catch-all route.

function App() {
  return (
    <Routes>
      <Route path="/" element={<Home />} />
      <Route path="/about" element={<About />} />
      <Route path="*" element={<NotFound />} />
    </Routes>
  );
}

function NotFound() {
  return <h1>404 - Page Not Found</h1>;
}

Complete Example

import React from 'react';
import { BrowserRouter as Router, Routes, Route, Link, useParams, useNavigate } from 'react-router-dom';

function App() {
  return (
    <Router>
      <div className="App">
        <nav>
          <Link to="/">Home</Link> | 
          <Link to="/about">About</Link> | 
          <Link to="/users">Users</Link>
        </nav>
        
        <Routes>
          <Route path="/" element={<Home />} />
          <Route path="/about" element={<About />} />
          <Route path="/users" element={<Users />} />
          <Route path="/users/:id" element={<User />} />
          <Route path="*" element={<NotFound />} />
        </Routes>
      </div>
    </Router>
  );
}

function Home() {
  return <h1>Home Page</h1>;
}

function About() {
  return <h1>About Page</h1>;
}

function Users() {
  return (
    <div>
      <h1>Users</h1>
      <ul>
        <li><Link to="/users/1">User 1</Link></li>
        <li><Link to="/users/2">User 2</Link></li>
      </ul>
    </div>
  );
}

function User() {
  const { id } = useParams();
  const navigate = useNavigate();
  
  return (
    <div>
      <h1>User {id}</h1>
      <button onClick={() => navigate('/users')}>Back to Users</button>
    </div>
  );
}

function NotFound() {
  return <h1>404 - Page Not Found</h1>;
}

export default App;

Best Practices

  1. Use index routes: For nested routes, use index prop for default child routes
  2. Organize routes logically: Group related routes together
  3. Use relative links: When possible, use relative paths in nested routes
  4. Handle loading states: Show loading indicators for async operations
  5. Test your routes: Ensure all navigation paths work correctly

Common Patterns

Layout Routes

function App() {
  return (
    <Routes>
      <Route path="/" element={<PublicLayout />}>
        <Route index element={<Home />} />
        <Route path="login" element={<Login />} />
      </Route>
      <Route path="/app" element={<AppLayout />}>
        <Route index element={<Dashboard />} />
        <Route path="profile" element={<Profile />} />
      </Route>
    </Routes>
  );
}

Route Parameters with Search

import { useSearchParams } from 'react-router-dom';

function SearchResults() {
  const [searchParams] = useSearchParams();
  const query = searchParams.get('q');
  
  return <div>Search results for: {query}</div>;
}

// URL: /search?q=react
<Route path="/search" element={<SearchResults />} />

External Resources:

Related Tutorials:

  • Learn more about React components here.
  • Check out React state management here for handling app state with routing.
Last updated on