React Router enables navigation between pages in a single-page application without full page reloads.

Installation

  npm install react-router-dom
  

Basic Setup

  // main.jsx
import { BrowserRouter } from 'react-router-dom';

ReactDOM.createRoot(document.getElementById('root')).render(
    <BrowserRouter>
        <App />
    </BrowserRouter>
);
  
  // App.jsx
import { Routes, Route, Link } from 'react-router-dom';
import Home from './pages/Home';
import About from './pages/About';
import NotFound from './pages/NotFound';

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

Route Parameters

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

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

function UserProfile() {
    const { id } = useParams();
    const [user, setUser] = useState(null);

    useEffect(() => {
        fetch(`/api/users/${id}`).then(r => r.json()).then(setUser);
    }, [id]);

    return user ? <h1>{user.name}</h1> : <p>Loading...</p>;
}
  
  import { Link, NavLink, useNavigate } from 'react-router-dom';

// Link
<Link to="/dashboard">Dashboard</Link>

// NavLink — active class
<NavLink to="/" className={({ isActive }) => isActive ? 'active' : ''}>
    Home
</NavLink>

// Programmatic navigation
function LoginForm() {
    const navigate = useNavigate();

    const handleLogin = async () => {
        await login();
        navigate('/dashboard');
        // navigate(-1) — go back
        // navigate('/users', { replace: true })
    };
}
  

Nested Routes

  // App.jsx
<Route path="/dashboard" element={<DashboardLayout />}>
    <Route index element={<Overview />} />
    <Route path="settings" element={<Settings />} />
    <Route path="profile" element={<Profile />} />
</Route>

// DashboardLayout.jsx
import { Outlet } from 'react-router-dom';

function DashboardLayout() {
    return (
        <div>
            <Sidebar />
            <main><Outlet /></main> {/* Child routes render here */}
        </div>
    );
}
  

Query Parameters

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

function SearchPage() {
    const [searchParams, setSearchParams] = useSearchParams();
    const query = searchParams.get('q') || '';

    return (
        <input
            value={query}
            onChange={e => setSearchParams({ q: e.target.value })}
        />
    );
}
  

Protected Routes

  function ProtectedRoute({ children }) {
    const { user } = useAuth();
    if (!user) return <Navigate to="/login" replace />;
    return children;
}

<Route path="/dashboard" element={
    <ProtectedRoute><Dashboard /></ProtectedRoute>
} />
  

Lazy Loading Routes

  import { lazy, Suspense } from 'react';

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

<Route path="/admin" element={
    <Suspense fallback={<p>Loading...</p>}>
        <Admin />
    </Suspense>
} />
  

React Router is the standard routing solution for React SPAs — pair it with data fetching libraries for full-featured apps.