🔐 React Router v6 中的私有路由

2025-05-27

🔐 React Router v6 中的私有路由

如今 WEB 领域瞬息万变,react-routerv6 已经进入测试阶段,即将面世。🤔

这仅用于学习目的,react-router v6 仍处于测试阶段,使用风险自负

v5 及以下版本中的私有路由是使用自定义组件以特定方式完成的,PrivateRoute该组件大多名为,大多数时候只是基本组件的包装和组合RouteRedirect例如

function PrivateRoute(props) {
  let { component: Component, children, render, ...rest } = props
  let auth = useAuth();
  return (
    <Route
      {...rest}
      render={() => auth
        ? <Component />
        : <Redirect to="/login" />
      }
    />
  );
}

function App() {
  return (
    <BrowserRouter>
      <Route path="/" component={Public} />
      <PrivateRoute path="/private" component={Private} />
    </BrowserRouter>
  );
}
Enter fullscreen mode Exit fullscreen mode

但是看一下 v6 文档,似乎情况发生了一些变化,我们需要对此进行一些不同的思考。

有关所有 API 参考的信息,请参阅链接

我们继续吧。

我们过去创造的一些东西PrivateRoute已经发生了一些变化

  • Redirect现在是Navigate
  • Routeprops 发生了变化,现在只是一个存根组件
  • Routes出现了一个新组件

在 v6 中,路线以这样的方式呈现

function App() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<Public />} />
        <Route path="/private" element={<Private />} />
      </Routes>
    </BrowserRouter>
  );
}

const Public = () => <div>public</div>;
const Private = () => <div>private</div>;
Enter fullscreen mode Exit fullscreen mode

所以如你所见,不再需要 render props 或 component props。
你需要传递一个直接的 JSX 元素(即使传递了也不用担心性能问题)。

好的,现在让我们看一下Route组件源代码

/**
 * Declares an element that should be rendered at a certain URL path.
 *
 * @see https://reactrouter.com/api/Route
 */
export function Route(_props: RouteProps): React.ReactElement | null {
  invariant(
    false,
    `A <Route> is only ever to be used as the child of <Routes> element, ` +
      `never rendered directly. Please wrap your <Route> in a <Routes>.`
  );
}
Enter fullscreen mode Exit fullscreen mode

等一下

等一下,代码在哪儿?👀 嗯,实际上,父组件Routes只会使用 来Route作为 props 和 children 的宿主,而不会对 做任何其他事情。Route

有关Routes实施的更多信息,请参见链接

那么我们PrivateRoute现在该如何实现呢?🤔 如果我们对 props 进行一些调整PrivateRoute,它看起来会像这样

function App() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<Public />} />
        <PrivateRoute path="/private" element={<Private />} />
      </Routes>
    </BrowserRouter>
  );
}
Enter fullscreen mode Exit fullscreen mode

但这行不通。Routes它只会获取 propsPrivateRoute并完全忽略其主体。甚至连里面的 console.logPrivateRoute都不会显示。

那么我们做什么呢?🤔 我们做了一些调整PrivateRoute

function PrivateRoute({ children }) {
  const auth = useAuth();
  return auth ? <>{children}</> : <Navigate to="/login" />;
}
Enter fullscreen mode Exit fullscreen mode

如你所见,我们将其改为RedirectNavigate并且仅在用户通过身份验证时返回children。它的用法也略有变化

function App() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<Public />} />
        <Route
          path="/private"
          element={
            <PrivateRoute>
              <Private />
            </PrivateRoute>
          }
        />
      </Routes>
    </BrowserRouter>
  );
}
Enter fullscreen mode Exit fullscreen mode

正如您所见,PrivateRoute也移动到了element道具。

的实现PrivateRoute可以通过多种方式完成。

PrivateRoute这是使用的不同实现Outlet

function PrivateOutlet() {
  const auth = useAuth();
  return auth ? <Outlet /> : <Navigate to="/login" />;
}

function App() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/private-outlet" element={<PrivateOutlet />}>
          <Route element={<Private />} />
        </Route>
      </Routes>
    </BrowserRouter>
  );
}
Enter fullscreen mode Exit fullscreen mode

这样做的好处是,您可以在同一路线下放置多个私有子路线。

完整示例请见Codesandbox

今天就到这里。祝你编程愉快!🎉 🎊 ✨

保证您的用户安全!

安全的

封面照片由Maxim ZhgulevUnsplash上拍摄

文章来源:https://dev.to/iamandrewluca/private-route-in-react-router-v6-lg5
PREV
软件工程师的 Git 命令
NEXT
DNS 基础知识:了解互联网的目录服务