路由守卫(导航守卫)
导航守卫(Navigation Guards)是 React Router 中用于在路由变化时执行特定逻辑的功能。它们可以用来验证用户权限、加载数据或阻止导航等。虽然 React Router 没有像 Vue Router 那样内置的全局导航守卫,但你可以通过几种方式实现类似的行为。
1. 使用高阶组件 (HOC) 或自定义 Hook
你可以在组件层级上使用 HOC 或自定义 Hook 来实现导航守卫逻辑。这通常涉及检查某些条件(如登录状态),并在满足条件时允许导航继续,否则重定向到其他页面或显示错误信息。
示例:自定义 Hook
jsx
import { useEffect } from 'react';
import { useHistory, useLocation } from 'react-router-dom';
function useRouteGuard(isAuthenticated) {
const history = useHistory();
const location = useLocation();
useEffect(() => {
if (!isAuthenticated) {
// 如果未认证,则重定向到登录页,并保存当前路径以便后续跳转回来
history.push({
pathname: '/login',
state: { from: location }
});
}
}, [isAuthenticated, history, location]);
}
// 在受保护的组件中使用
function ProtectedComponent() {
const isAuthenticated = /* 你的认证逻辑 */;
useRouteGuard(isAuthenticated);
return <div>Protected Content</div>;
}2. 使用 Prompt 组件(v5)
React Router v5 提供了一个名为 <Prompt> 的组件,它可以阻止用户离开当前页面,直到他们确认是否真的要离开。这对于防止用户意外丢失未保存的数据非常有用。
示例:Prompt
jsx
import { Prompt } from "react-router-dom";
function FormWithPrompt({ isBlocking }) {
return (
<form>
{/* 表单内容 */}
<Prompt
when={isBlocking}
message="Are you sure you want to leave? You have unsaved changes."
/>
</form>
);
}3. 自定义中间件(适用于更复杂的场景)
对于更复杂的需求,比如基于角色的访问控制或动态加载资源,你可以创建一个自定义中间件来拦截所有的路由变化。这可以通过监听 history.listen 事件来实现。
示例:全局导航守卫
jsx
import { createBrowserHistory } from "history";
import { useEffect } from "react";
import { useHistory } from "react-router-dom";
const customHistory = createBrowserHistory();
function useGlobalGuard() {
const history = useHistory();
useEffect(() => {
const unlisten = customHistory.listen((location, action) => {
// 在这里添加你的守卫逻辑
console.log("The current URL is", location.pathname);
console.log("It changed via", action); // PUSH, REPLACE, POP
// 根据需要执行一些操作,例如:
// - 检查用户是否已登录
// - 加载必要的数据
// - 显示加载指示器
// - 等等...
});
return () => {
unlisten();
};
}, [history]);
}
// 在应用顶层使用此 Hook
function App() {
useGlobalGuard();
// 其他应用代码...
}4. 使用 useEffect 监听 location 变化(v6)
React Router v6 不再支持 <Prompt> 组件,但是你可以利用 useEffect 和 useLocation Hooks 来监听位置变化并实施相应的逻辑。
示例:监听位置变化
jsx
import { useEffect, useState } from 'react';
import { useLocation, Navigate } from 'react-router-dom';
function RouteGuard({ children, isAllowed }) {
const [redirected, setRedirected] = useState(false);
const location = useLocation();
useEffect(() => {
if (!isAllowed) {
setRedirected(true);
}
}, [location, isAllowed]);
if (redirected) {
return <Navigate to="/unauthorized" />;
}
return children;
}
// 使用 RouteGuard 包装受保护的组件
function ProtectedPage() {
const isAuthenticated = /* 你的认证逻辑 */;
return (
<RouteGuard isAllowed={isAuthenticated}>
<h1>This is a protected page</h1>
</RouteGuard>
);
}总结
虽然 React Router 没有直接提供类似于 Vue Router 的全局导航守卫 API,但你可以通过上述方法实现类似的功能。选择哪种方法取决于你的具体需求和项目的复杂度:
- 自定义 Hook:适合于组件级别的导航守卫。
<Prompt>(仅限 v5):用于阻止用户离开表单或其他页面。- 自定义中间件:适用于需要对所有路由变化进行全局处理的情况。
- 监听
location变化(v6):一种灵活的方式来响应路由的变化。