Back to Blog
By AriesZhou · · 4 min read

React Router

React

React Router is the most popular routing library in the React ecosystem. It keeps the URL and UI in sync in single-page applications (SPAs) without requiring page refreshes. This article focuses on the core concepts and practical usage of React Router v6.

1. Core components

React Router v6 provides several core components for defining and managing routes:

1.1 Router component

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

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

Note: v6 replaces v5’s <Switch> with <Routes>, and the <Route> component now uses the element prop instead of component.

ComponentPurpose
BrowserRouterUses the HTML5 History API and supports clean URLs
HashRouterUses the URL hash portion and is suitable for environments without History API support
MemoryRouterIn-memory router, often used for testing
import { Link, NavLink } from 'react-router-dom';

// 普通链接 - 不会触发页面刷新
<Link to="/about">关于</Link>

// 导航链接 - 可添加激活样式
<NavLink
  to="/profile"
  className={({ isActive }) => isActive ? 'active' : ''}
>
  个人资料
</NavLink>

2. Route parameters

2.1 Dynamic route parameters

Use :参数名 to define dynamic path segments:

<Routes>
  <Route path="/user/:userId" element={<UserProfile />} />
  <Route path="/post/:postId/comments/:commentId" element={<Comment />} />
</Routes>

2.2 Accessing route parameters

v6 uses the useParams hook to access parameters:

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

function UserProfile() {
  const { userId } = useParams();

  return <h1>用户 ID: {userId}</h1>;
}

Tip: Compared to v5’s this.props.match.params, the Hook approach is cleaner and works well with function components.

3. Programmatic navigation

3.1 useNavigate Hook

v6 uses useNavigate instead of the history object:

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

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

  const handleLogin = () => {
    // 登录逻辑...
    navigate('/dashboard');
  };

  return <button onClick={handleLogin}>登录</button>;
}

3.2 Navigation options

const navigate = useNavigate();

// 替换当前历史记录
navigate('/new-page', { replace: true });

// 带状态导航
navigate('/user/123', { state: { from: '/login' } });

3.3 Accessing navigation state

Use useLocation to get current location info:

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

function Breadcrumb() {
  const location = useLocation();

  // location.pathname = "/user/123"
  // location.state = { from: "/login" }
  // location.search = "?tab=profile"

  return <div>当前位置: {location.pathname}</div>;
}

4. Nested routes

4.1 Nested route structure

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

function Layout() {
  return (
    <div>
      <nav>
        <Link to="/">首页</Link>
        <Link to="/dashboard">仪表盘</Link>
        <Link to="/settings">设置</Link>
      </nav>
      <Outlet />
    </div>
  );
}

Key change: v6 uses <Outlet> component to render child routes, a major improvement over the v5 nesting approach.

4.2 Nested route parameters

<Routes>
  <Route path="/user" element={<UserLayout />}>
    <Route path=":userId" element={<UserProfile />} />
    <Route path=":userId/posts" element={<UserPosts />} />
  </Route>
</Routes>
function UserProfile() {
  const { userId } = useParams();
  return <div>用户 {userId} 的主页</div>;
}

5. Route guards

5.1 Protecting private routes

v6 recommends using Outlet to implement route guards:

function PrivateRoute({ isAuthenticated }) {
  return isAuthenticated ? <Outlet /> : <Navigate to="/login" />;
}

function App() {
  const isAuthenticated = useAuth(); // 自定义认证逻辑

  return (
    <Routes>
      <Route path="/login" element={<Login />} />
      <Route element={<PrivateRoute isAuthenticated={isAuthenticated} />}>
        <Route path="/dashboard" element={<Dashboard />} />
        <Route path="/profile" element={<Profile />} />
      </Route>
    </Routes>
  );
}

5.2 Conditional redirects

function RedirectIfLoggedIn({ children }) {
  const { isAuthenticated } = useAuth();
  const location = useLocation();

  if (isAuthenticated) {
    return <Navigate to="/dashboard" state={{ from: location }} replace />;
  }

  return children;
}

6. Route matching and priority

6.1 Exact matching

v6 uses exact matching by default:

// 精确匹配 "/" - 不会匹配 "/about"
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />

// 使用 * 匹配任意路径
<Route path="/products/*" element={<ProductRoutes />} />

6.2 404 Page

<Routes>
  <Route path="/" element={<Home />} />
  <Route path="*" element={<NotFound />} />
</Routes>

7. v5 to v6 Migration Reference Table

v5 syntaxv6 syntax
<Switch><Routes>
component={User}element={<User />}
render={() => <User />}element={<User />}
this.props.history.push()useNavigate()
this.props.match.paramsuseParams()
<Redirect to="/path" /><Navigate to="/path" />
Nested routes use props.childrenUse <Outlet />

8. Summary

React Router v6 brings several important improvements:

  • Hooks first: Hooks are recommended for accessing route information, making code cleaner
  • Outlet component: Simplifies implementing nested routes
  • Routes upgrade: Automatically picks the best match, no more manual ordering
  • Navigate component: Unifies redirect logic

These changes make route configuration more declarative and the code more maintainable.