React Router v6:路由管理的最新进展

React Router v6 是 React 应用程序路由管理的一个重大更新,它引入了许多改进和简化,包括对嵌套路由的更友好处理,以及对钩子函数的使用。

2500G计算机入门到高级架构师开发资料超级大礼包免费送!

1. Routes 重构

在 v6 中,<Route> 组件被替换为 <Routes> 组件,后者用于包裹所有路由。此外,Switch 组件不再存在,因为 <Routes> 已经实现了类似于 Switch 的行为,只会匹配并渲染第一个匹配的路由。

jsx 复制代码
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';

function App() {
  return (
    <Router>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/about" element={<About />} />
        <Route path="/users/*" element={<Users />} /> {/* 通配符支持 */}
      </Routes>
    </Router>
  );
}

2. 使用 element 属性

路由现在通过 element 属性指定要渲染的组件,而不是通过 componentrender 函数。

jsx 复制代码
<Route path="/profile/:userId" element={<Profile />} />

3. Hook API

React Router v6 引入了新的钩子函数,如 useHistory, useLocation, useParams, 和 useNavigate,这些钩子允许在组件内部直接处理导航。

jsx 复制代码
import { useParams } from 'react-router-dom';

function Profile() {
  const { userId } = useParams();
  return <div>Profile of user {userId}</div>;
}

useNavigate 钩子返回一个 navigate 函数,用于在组件内部导航。

jsx 复制代码
import { useNavigate } from 'react-router-dom';

function ProfileForm() {
  const navigate = useNavigate();
  const handleSubmit = (event) => {
    event.preventDefault();
    // 提交表单后导航到另一个页面
    navigate('/success', { replace: true }); // 替换当前历史记录
  };

  return <form onSubmit={handleSubmit}>...</form>;
}

5. 懒加载和代码分割

React Router v6 支持动态导入,这有助于实现代码分割,提高应用的加载速度。

jsx 复制代码
<Route path="/lazy" element={import('./LazyComponent').then((mod) => mod.LazyComponent)} />

6. 404 页面

处理未找到的路由,可以设置一个通配符路由来捕获所有未匹配的路径。

jsx 复制代码
<Route path="*" element={<Error404 />} />

7. 嵌套路由

嵌套路由的处理更加简洁,使用 Routes 和 Route 的组合即可。

jsx 复制代码
function App() {
  return (
    <Router>
      <Routes>
        <Route path="/" element={<MainLayout />}>
          <Route index element={<Home />} />
          <Route path="about" element={<About />} />
          <Route path="users" element={<Users />}>
            <Route path=":userId" element={<User />} />
          </Route>
        </Route>
        <Route path="*" element={<Error404 />} />
      </Routes>
    </Router>
  );
}

8. 路由保护和权限控制

在React Router v6中,可以使用 useEffectuseLayoutEffect 钩子以及 useNavigate 来实现路由保护,确保用户在登录后才能访问受保护的路由。

jsx 复制代码
import { useNavigate, useLocation } from 'react-router-dom';

function PrivateRoute({ children }) {
  const location = useLocation();
  const navigate = useNavigate();

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

  return isAuthenticated() ? children : null;
}

function App() {
  return (
    <Router>
      <Routes>
        <Route path="/" element={<PublicRoute><Home /></PublicRoute>} />
        <Route path="/dashboard" element={<PrivateRoute><Dashboard /></PrivateRoute>} />
        <Route path="/login" element={<Login />} />
      </Routes>
    </Router>
  );
}

在这个例子中,isAuthenticated() 是一个假设的函数,检查用户是否已登录。如果用户未登录,他们将被重定向到登录页面。

9. 重定向和重定位

在 v6 中,可以使用 Navigate 组件来实现重定向。它类似于一个特殊的元素,会触发导航到指定的URL。

jsx 复制代码
import { Navigate } from 'react-router-dom';

function PrivateRoute({ children }) {
  if (!isAuthenticated()) {
    return <Navigate to="/login" replace />;
  }

  return children;
}

10. 路由参数和查询字符串

在 v6 中,你可以使用 useParams 钩子获取路由参数,使用 useLocation 获取查询字符串。

jsx 复制代码
import { useParams, useLocation } from 'react-router-dom';

function Profile() {
  const { userId } = useParams();
  const query = new URLSearchParams(useLocation().search);
  const searchParam = query.get('paramName');

  return <div>Profile of user {userId} with search param: {searchParam}</div>;
}

11. 自定义路由匹配

React Router v6 允许你通过 path-to-regexp 库自定义路由匹配规则,但通常情况下,标准的路径模式已经足够使用。

12. 高阶组件(HoC)

尽管 v6 中不再推荐使用高阶组件,但你仍然可以通过包装组件来实现特定逻辑,如路由保护。

jsx 复制代码
function PrivateRoute({ children }) {
  if (!isAuthenticated()) {
    return <Navigate to="/login" replace />;
  }

  return <>{children}</>;
}

function App() {
  return (
    <Router>
      <Routes>
        <Route path="/" element={<PublicRoute><Home /></PublicRoute>} />
        <Route path="/dashboard" element={<PrivateRoute><Dashboard /></PrivateRoute>} />
        <Route path="/login" element={<Login />} />
      </Routes>
    </Router>
  );
}

13. 路由事件

React Router v6 提供了一些生命周期事件,如 useRouteMatchuseLocationuseHistoryuseNavigate。这些钩子可以帮助你在组件中监听路由变化并做出响应。

jsx 复制代码
import { useLocation } from 'react-router-dom';

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

  useEffect(() => {
    console.log(`Navigated to ${location.pathname}`);
  }, [location]);

  return /* ... */;
}

14. 路由配置的模块化

为了保持代码的整洁,你可以将路由配置分散到多个模块中,然后在主配置文件中导入并合并它们。

jsx 复制代码
// routes/users.js
export default [
  { path: '/users', element: <UsersList /> },
  { path: '/users/:id', element: <UserProfile /> },
];

// routes/admin.js
export default [
  { path: '/admin/dashboard', element: <AdminDashboard /> },
  { path: '/admin/users', element: <AdminUsers /> },
];

// App.js
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
import usersRoutes from './routes/users';
import adminRoutes from './routes/admin';

function App() {
  return (
    <Router>
      <Routes>
        {usersRoutes.map((route, index) => (
          <Route key={index} {...route} />
        ))}
        {adminRoutes.map((route, index) => (
          <Route key={index} {...route} />
        ))}
        {/* 错误页面或404页面 */}
        <Route path="*" element={<ErrorPage />} />
      </Routes>
    </Router>
  );
}

15. 路由守卫(Guard)

你可以创建自定义的守卫函数来决定用户是否可以访问某个路由。这通常用于实现权限验证或数据预加载。

jsx 复制代码
function requireAuth(nextState, replace) {
  if (!isAuthenticated()) {
    replace({
      pathname: '/login',
      state: { nextPathname: nextState.location.pathname },
    });
  }
}

// 在路由中使用
<Route path="/protected" onEnter={requireAuth} component={ProtectedComponent} />

在 v6 中,可以使用 useEffect 或 useLayoutEffect 钩子来实现类似的功能。

16. 路由嵌套

虽然在 v6 中不再需要显式地包裹 Switch 组件,但嵌套路由的概念仍然存在。你可以通过在路由配置中嵌套 Routes 来实现。

jsx 复制代码
function App() {
  return (
    <Router>
      <Routes>
        <Route path="/" element={<MainLayout />}>
          <Route index element={<Home />} />
          <Route path="about" element={<About />} />
          <Route path="users" element={<Users />}>
            <Route path=":userId" element={<User />} />
          </Route>
        </Route>
        <Route path="*" element={<Error404 />} />
      </Routes>
    </Router>
  );
}

在这个例子中,/users/:userId 路由是在 /users 路由内部定义的,这意味着在访问 /users/someId 时,Users 组件会被渲染,同时 User 组件也会被渲染。

17. 自定义错误处理

React Router v6 不再提供全局错误处理,但你可以通过监听 window.onError 或使用自定义中间件来实现。

18. 代码分割和懒加载

React Router v6 与 Webpack 或其他打包工具很好地配合,可以实现代码分割和懒加载。你可以使用 import() 动态导入组件来实现这一点。

jsx 复制代码
<Route
  path="/lazy"
  element={
    import('./LazyComponent')
      .then((mod) => mod.LazyComponent)
      .catch((error) => <ErrorBoundary error={error} />)
  }
/>

19. 自定义路由组件

虽然 Route 组件在 v6 中已经非常简单,但你仍然可以创建自己的组件来扩展其功能,例如添加自定义的加载指示器。

20. 服务器端渲染(SSR)

React Router v6 支持服务器端渲染,但需要额外的配置和库,如 react-router-dom/serverreact-router-dom/browser

2500G计算机入门到高级架构师开发资料超级大礼包免费送!

相关推荐
喵叔哟18 分钟前
重构代码之取消临时字段
java·前端·重构
还是大剑师兰特1 小时前
D3的竞品有哪些,D3的优势,D3和echarts的对比
前端·javascript·echarts
王解1 小时前
【深度解析】CSS工程化全攻略(1)
前端·css
一只小白菜~1 小时前
web浏览器环境下使用window.open()打开PDF文件不是预览,而是下载文件?
前端·javascript·pdf·windowopen预览pdf
方才coding1 小时前
1小时构建Vue3知识体系之vue的生命周期函数
前端·javascript·vue.js
阿征学IT1 小时前
vue过滤器初步使用
前端·javascript·vue.js
王哲晓1 小时前
第四十五章 Vue之Vuex模块化创建(module)
前端·javascript·vue.js
丶21361 小时前
【WEB】深入理解 CORS(跨域资源共享):原理、配置与常见问题
前端·架构·web
发现你走远了1 小时前
『VUE』25. 组件事件与v-model(详细图文注释)
前端·javascript·vue.js
Mr.咕咕1 小时前
Django 搭建数据管理web——商品管理
前端·python·django