大家好,我是一个不小心把路由玩坏了的前端人。
今天给大家拆一拆一个超级常用、却经常被初学者绕晕的组合技能:
前端路由守卫 ProtectRoute + 懒加载
搞完这套,你就可以:
- 限制没登录的人访问付费页
- 实现大型项目的按需加载,不用一次性全拉页面
- 再也不用怕后端大哥问:"你这页面谁都能看啊?"
别废话,开干!
场景:谁需要 ProtectRoute?
假设你有个电商网站,里面有个 /pay 页面。
顾客必须登录后才能访问,否则就要把人轰到登录页。
没有路由守卫时,别人只要在浏览器地址栏输入
/pay,就直接进来了,付费啥的都白搞了。
所以我们要搞个路由守卫,守卫就是拦路虎:
- 登录了? 过关,看内容!
- 没登录? 抱歉兄弟,给我去
/login。
ProtectRoute 的灵魂
在 React + React Router 里,我们要做的事情很简单:
- 判断当前用户有没有登录
- 没登录就用
<Navigate />跳转去/login - 登录了就把该看的页面原样放出来
这就是 ProtectRoute 的全部核心。
来看一眼完整的 ProtectRoute.jsx:
jsx
import {
Navigate,
useLocation
} from 'react-router-dom';
// 鉴权组件
const ProtectRoute = (props) => {
const { children } = props; // 包裹的子内容
const { pathname } = useLocation(); // 当前访问路径
const isLogin = localStorage.getItem('isLogin') === 'true'; // 登录标记
if (!isLogin) {
// 没登录就跳去 login,并带上来源路径
return <Navigate to="/login" state={{ from: pathname }} />;
}
// 登录了,放行!
return children;
};
export default ProtectRoute;
有没有发现,它其实啥也不渲染,只是做判断:
- 没登录?拦截 + 重定向。
- 登录了?把包裹的内容(子组件)放出来。如果用户未指定跳转 /pay → 不会自动跳转,而是显示当前访问的受保护页面
登录页怎么写?
ProtectRoute 只能拦截,具体登录验证得在 /login 页面里搞定。
来看一个极简示例 Login.jsx:
jsx
import { useState } from 'react';
import {
useNavigate,
useLocation
} from 'react-router-dom';
const Login = () => {
const navigate = useNavigate();
const location = useLocation();
const [username, setUsername] = useState('');
const [password, setPassword] = useState('');
const handleSubmit = (e) => {
e.preventDefault();
if (username === 'admin' && password === '123456') {
localStorage.setItem('isLogin', true);
// 登录成功,跳回来源路径,否则去首页
navigate(location?.state?.from || '/');
} else {
alert('用户名或密码错误');
}
};
return (
<form onSubmit={handleSubmit}>
<h1>登录</h1>
<input
type="text"
placeholder="用户名"
value={username}
onChange={(e) => setUsername(e.target.value)}
required
/>
<input
type="password"
placeholder="密码"
value={password}
onChange={(e) => setPassword(e.target.value)}
required
/>
<button type="submit">登录</button>
</form>
);
};
export default Login;
小点:
- 我用
localStorage储存登录状态,这种方式够演示用了,生产环境记得用 Token + 后端校验。 - 登录后
navigate跳转,带着from,回到刚刚被拦住的页面。 - 这个from的调用需要用useLocation这个hooks才能执行,同时这个location.state.from已经在前面ProtectRoute代码中用state赋值了'/pay',所以这里才能直接使用这个实现
- 同时导入useNavigate这个hooks函数,用Navigate属性跳转该页面。
ProtectRoute 怎么用?
放在 Route 上包裹就完事儿!
看这段:
jsx
<Route path="/pay" element={
<ProtectRoute>
<Pay />
</ProtectRoute>
} />
意思就是:
- 有
ProtectRoute守着/pay。 - 只有登录了,
<Pay />才能显示。
5 再来点实用的:路由懒加载
**大型项目往往页面多,**如果一次性全加载,首屏加载要半天。
所以 React 提供了懒加载(React.lazy + Suspense):
看我改造后的 App.jsx:
jsx
import { Suspense, lazy } from 'react';
import {
BrowserRouter as Router,
Routes,
Route
} from 'react-router-dom';
import Navigation from './components/Navigation';
import ProtectRoute from './pages/ProtectRoute';
// 懒加载
const Home = lazy(() => import('./pages/Home'));
const About = lazy(() => import('./pages/About'));
const Pay = lazy(() => import('./pages/Pay'));
const Login = lazy(() => import('./pages/Login'));
const NotFound = lazy(() => import('./pages/NotFound'));
function App() {
return (
<Router>
<Navigation />
<Suspense fallback={<div>页面加载中...</div>}>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/login" element={<Login />} />
<Route
path="/pay"
element={
<ProtectRoute>
<Pay />
</ProtectRoute>
}
/>
<Route path="*" element={<NotFound />} />
</Routes>
</Suspense>
</Router>
);
}
export default App;
关键点:
lazy是按需加载。Home、About、Pay等页面只有真正访问时才会被请求。Suspense是个兜底,加载过程中显示<div>页面加载中...</div>,避免用户盯着空白发呆。
完整执行流:串起来
-
用户访问
/pay。 -
ProtectRoute检查登录状态:- 没登录:拦截,跳去
/login,带上来源/pay。 - 登录了:正常显示
<Pay />页面。
- 没登录:拦截,跳去
-
用户在
/login输入正确账号密码,localStorage标记登录成功。 -
登录成功后,
navigate把用户送回来源页面/pay,用户开心付钱。
总结一句话
这套组合就是:
ProtectRoute:路由守卫,没登录别想看。<Navigate />:拦截后跳转去登录。localStorage:临时保存登录状态(演示用)。- 懒加载
React.lazy+Suspense:页面多也不怕,按需拉取,首屏更快。
🎉 写在最后
这就是一个最小可用、适合新手上手的前端路由权限保护 + 懒加载组合。
你可以直接用:
- 做会员专区
- 做后台管理系统
- 做只能登录后看的页面
如果你以后要更安全一点,可以把 localStorage 换成 cookie + token,并且请求后端校验。
前端的世界很简单,做对了就像拉闸限电,做错了就是裸奔。
希望这篇小白也能看懂,如果觉得有用,记得点赞、收藏、转发,不然你的路由可能又被白嫖了哦!
有需要完整示例文件的,评论区告诉我,给你一份打包好的版本,开箱即用。
完,撒花!