You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Router 6.4私有路由配置报错,咨询正确实现方式

React Router 6.4 正确实现私有路由的方法

问题场景

我使用React Router的createBrowserRouter新特性配置路由,代码如下:

const router = createBrowserRouter(
  createRoutesFromElements(
    <Route path="/" element={<RootLayout />}>
      <Route index element={<Landing />} />
      <Route path="login" element={<Login />} />
      <Route path="signup" element={<SignUp />} />
      <Route path="manager" element={<ManagerLayout />}>
        <Route index path="dashboard" element={<Dashboard />} />
        <Route path="team" element={<TeamLayout />}>
          <Route path="personel" element={<Personel />} />
        </Route>
        <Route path="profile" element={<Profile />} />
      </Route>
      <Route path="*" element={<NotFound />} />
    </Route>
  )
)

function App() {
  return (
    <AuthProvider>
      <RouterProvider router={router} />
    </AuthProvider>
  );
}

为了限制部分路由的访问权限,我创建了如下PrivateRoute组件:

import React from 'react';
import { Route, Navigate } from 'react-router-dom';
import { useAuth } from './globalContext';

function PrivateRoute({ element, ...rest }) {
    const { isLoggedIn } = useAuth();

    return isLoggedIn ? (
        <Route {...rest} element={element} />
    ) : (
        <Navigate to="/login" replace />
    );
}

export default PrivateRoute;

但运行时出现报错:

Uncaught Error: [PrivateRoute] is not a <Route> component. All component children of <Routes> must be a <Route> or <React.Fragment>

原因分析

React Router 6.4+ 采用了新的路由配置模式(createBrowserRouter/RouterProvider),不再支持自定义类似PrivateRoute的组件作为Route的子元素。路由配置结构要求严格,所有直接子元素必须是官方的<Route>或<React.Fragment>,自定义组件返回<Route>的方式不再适用。

正确实现方式

方法一:使用权限包裹组件(推荐)

创建一个用于包裹需要权限验证的路由元素的组件,通过控制是否渲染子元素来实现权限拦截:

import { Navigate, useLocation } from 'react-router-dom';
import { useAuth } from './globalContext';

function PrivateWrapper({ children }) {
  const { isLoggedIn } = useAuth();
  const location = useLocation();

  // 未登录时跳转到登录页,保存当前位置以便登录后返回
  if (!isLoggedIn) {
    return <Navigate to="/login" state={{ from: location }} replace />;
  }

  return children;
}

然后修改路由配置,将需要保护的路由的element用PrivateWrapper包裹:

const router = createBrowserRouter(
  createRoutesFromElements(
    <Route path="/" element={<RootLayout />}>
      <Route index element={<Landing />} />
      <Route path="login" element={<Login />} />
      <Route path="signup" element={<SignUp />} />
      {/* 用PrivateWrapper包裹需要保护的父路由,子路由会自动继承权限验证 */}
      <Route path="manager" element={<PrivateWrapper><ManagerLayout /></PrivateWrapper>}>
        <Route index path="dashboard" element={<Dashboard />} />
        <Route path="team" element={<TeamLayout />}>
          <Route path="personel" element={<Personel />} />
        </Route>
        <Route path="profile" element={<Profile />} />
      </Route>
      <Route path="*" element={<NotFound />} />
    </Route>
  )
);

这种方式符合React Router 6.4+的设计逻辑,将权限验证逻辑与路由配置解耦,同时可以灵活控制单个或多个路由的权限。

方法二:使用路由Loader进行权限验证

利用React Router 6.4新增的loader钩子,在路由加载前进行权限检查,若未登录则触发重定向:

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

// 注意:loader函数中不能直接使用React Hooks,需改为直接访问全局状态或调用API验证
export const authLoader = () => {
  // 实际项目中建议调用后端API验证登录状态,而非仅依赖前端状态
  const auth = JSON.parse(localStorage.getItem('auth'));
  const isLoggedIn = auth?.isLoggedIn;

  if (!isLoggedIn) {
    // 重定向到登录页并携带当前路径
    throw redirect({
      pathname: '/login',
      state: { from: window.location.pathname },
    });
  }
  return null;
};

修改路由配置,给需要保护的路由添加loader:

const router = createBrowserRouter(
  createRoutesFromElements(
    <Route path="/" element={<RootLayout />}>
      <Route index element={<Landing />} />
      <Route path="login" element={<Login />} />
      <Route path="signup" element={<SignUp />} />
      {/* 添加authLoader进行权限验证 */}
      <Route 
        path="manager" 
        element={<ManagerLayout />}
        loader={authLoader}
      >
        <Route index path="dashboard" element={<Dashboard />} />
        <Route path="team" element={<TeamLayout />}>
          <Route path="personel" element={<Personel />} />
        </Route>
        <Route path="profile" element={<Profile />} />
      </Route>
      <Route path="*" element={<NotFound />} />
    </Route>
  )
);

该方法适合需要在路由加载前执行异步验证(如检查token有效性)的场景,通过抛出redirect实现自动跳转。

内容的提问来源于stack exchange,提问作者jchm

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 01:07:05