React Router
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 theelementprop instead ofcomponent.
| Component | Purpose |
|---|---|
BrowserRouter | Uses the HTML5 History API and supports clean URLs |
HashRouter | Uses the URL hash portion and is suitable for environments without History API support |
MemoryRouter | In-memory router, often used for testing |
1.2 Link and NavLink
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 syntax | v6 syntax |
|---|---|
<Switch> | <Routes> |
component={User} | element={<User />} |
render={() => <User />} | element={<User />} |
this.props.history.push() | useNavigate() |
this.props.match.params | useParams() |
<Redirect to="/path" /> | <Navigate to="/path" /> |
Nested routes use props.children | Use <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.