本文目录导读:
- 案例需求定义
- React (基于 Hooks + Context API / 或 Zustand)
- Vue 3 (基于 Composition API + Pinia)
- Angular (基于 Service + HttpClient + Route Guards)
- 横向对比总结表
- 决定性的选择建议
这是一个非常经典且具有实际意义的命题,通过一个用户认证系统(包含注册、登录、Token验证、权限路由)的案例,可以清晰地对比 React(Next.js/SPA)、Vue(Nuxt.js/SPA) 和 Angular(独立框架) 这三者在 工程化思维、响应式机制、状态管理、以及路由守卫 上的核心差异。
下面我将用一个统一的业务需求来拆解对比:
案例需求定义
- API 接口:
POST /api/login(返回 JWT Token),GET /api/user/profile(需 Bearer Token 验证)。 - UI 界面:登录页(Login)、仪表盘页(Dashboard,需登录)、404 页。
- 核心逻辑:
- 用户登录成功后,Token 存入
localStorage。 - 页面刷新后,自动从
localStorage读取 Token 并验证用户身份。 - 未登录用户访问 Dashboard 时,自动重定向到登录页(路由守卫)。
- 支持用户登出。
- 用户登录成功后,Token 存入
React (基于 Hooks + Context API / 或 Zustand)
实现哲学:函数式、单向数据流、显式状态提升,没有官方的路由和 HTTP 模块,通常依赖 react-router-dom 和 fetch/axios。
核心代码思路
-
身份状态管理(Context + useReducer)
// AuthContext.js const AuthContext = createContext(); const authReducer = (state, action) => { switch (action.type) { case 'LOGIN_SUCCESS': return { ...state, user: action.payload, token: action.token }; case 'LOGOUT': return { ...state, user: null, token: null }; default: return state; } }; export const AuthProvider = ({ children }) => { const [state, dispatch] = useReducer(authReducer, { user: null, token: localStorage.getItem('token') }); // 初始化时检查Token useEffect(() => { if (state.token) { fetch('/api/user/profile', { headers: { Authorization: `Bearer ${state.token}` } }) .then(res => res.json()) .then(data => dispatch({ type: 'LOGIN_SUCCESS', payload: data, token: state.token })) .catch(() => dispatch({ type: 'LOGOUT' })); } }, []); return <AuthContext.Provider value={{ state, dispatch }}>{children}</AuthContext.Provider>; }; -
路由守卫(Wrapper 组件)
// PrivateRoute.js const PrivateRoute = ({ children }) => { const { state } = useContext(AuthContext); const location = useLocation(); // 若用户为null且Token存在代表正在加载,显示loading;若用户为null且无Token则重定向 if (!state.user && state.token) return <div>Loading...</div>; return state.user ? children : <Navigate to="/login" state={{ from: location }} replace />; };
- 灵活性高:路由守卫通过组件包裹实现,任何逻辑都可插入。
- 状态显式:
useReducer强制显式处理 action。 - 依赖外部:需要自己选择
react-router和 HTTP 库。
Vue 3 (基于 Composition API + Pinia)
实现哲学:响应式代理、声明式、渐进增强,Vue 的响应式系统(ref、reactive)让状态管理变得非常直觉,官方推荐 vue-router 和 Pinia。
核心代码思路
-
身份状态管理(Pinia Store)
// stores/auth.js export const useAuthStore = defineStore('auth', () => { const user = ref(null); const token = ref(localStorage.getItem('token')); const isAuthenticated = computed(() => !!user.value); // 响应式计算属性 async function init() { if (token.value) { try { const res = await fetch('/api/user/profile', { headers: { Authorization: `Bearer ${token.value}` } }); user.value = await res.json(); } catch { logout(); } } } async function login(credentials) { /* ... */ } function logout() { user.value = null; token.value = null; localStorage.removeItem('token'); } return { user, token, isAuthenticated, init, login, logout }; }); -
路由守卫(Navigation Guard)
// router/index.js import { useAuthStore } from '@/stores/auth'; router.beforeEach(async (to, from, next) => { const authStore = useAuthStore(); if (to.meta.requiresAuth) { // 关键:如果还没初始化用户数据,等待init完成 if (!authStore.user && authStore.token) { await authStore.init(); } if (authStore.user) { next(); } else { next({ name: 'Login', query: { redirect: to.fullPath } }); } } else { next(); } });
- 响应式极其自然:
computed自动追踪依赖。 - 路由守卫是“函数”:Vue Router 的
beforeEach是全局前置守卫,逻辑集中且支持async/await。 - Store 零样板:Pinia 的 Composition API 写法非常接近普通 JS 逻辑。
Angular (基于 Service + HttpClient + Route Guards)
实现哲学:强类型、面向对象、依赖注入(DI),Angular 提供全栈式官方方案:HttpClientModule、RouterModule、Guards、Interceptors。
核心代码思路
-
身份状态管理(Service + RxJS Subject)
// auth.service.ts @Injectable({ providedIn: 'root' }) export class AuthService { private userSubject = new BehaviorSubject<User | null>(null); user$ = this.userSubject.asObservable(); // 供组件订阅 constructor(private http: HttpClient) { const token = localStorage.getItem('token'); if (token) { this.http.get<User>('/api/user/profile') .subscribe({ next: user => this.userSubject.next(user), error: () => this.logout() }); } } get currentUserValue(): User | null { return this.userSubject.value; } login(creds: { username: string; password: string }) { return this.http.post<{ token: string }>('/api/login', creds).pipe( tap(res => { localStorage.setItem('token', res.token); }) ); } } -
路由守卫(Guard Class)
// auth.guard.ts @Injectable({ providedIn: 'root' }) export class AuthGuard implements CanActivate { constructor(private authService: AuthService, private router: Router) {} canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean { if (this.authService.currentUserValue) { return true; } this.router.navigate(['/login'], { queryParams: { returnUrl: state.url } }); return false; } }// app-routing.module.ts const routes: Routes = [ { path: 'dashboard', component: DashboardComponent, canActivate: [AuthGuard] } ]; -
HTTP 拦截器(自动注入 Token)
// jwt.interceptor.ts @Injectable() export class JwtInterceptor implements HttpInterceptor { intercept(req: HttpRequest<any>, next: HttpHandler) { const token = localStorage.getItem('token'); if (token) { req = req.clone({ setHeaders: { Authorization: `Bearer ${token}` } }); } return next.handle(req); } }
- 强类型与 DI:Service 通过 DI 注入,代码清晰可测。
- 拦截器机制:自动处理 Token 注入和 401 错误,是三大框架中内置最完善的。
- 路由守卫是“类”:强制分离关注点,通过
canActivate接口实现。 - RxJS 生态:异步操作(如
user$)完全基于 Observable,上手门槛稍高。
横向对比总结表
| 维度 | React (SPA) | Vue 3 (SPA) | Angular |
|---|---|---|---|
| 状态管理 | Context + useReducer / Zustand(手动) | Pinia / Vuex(官方推荐) | Service + BehaviorSubject(官方内置) |
| 路由守卫 | 组件式 <PrivateRoute>(灵活但分散) |
全局 beforeEach(集中、异步友好) |
类式 Guard(canActivate、可复用) |
| HTTP 拦截 | 无原生,需 axios 拦截器 |
无原生,需 axios 拦截器 |
原生 HttpInterceptor(非常强大) |
| 响应式机制 | 通过 useState/useReducer 触发重新渲染 |
基于 Proxy 的响应式代理(自动追踪) | Zone.js + ChangeDetection(脏检查) |
| TypeScript | 支持(可选,通过 JSDoc/TSX) | 支持(优秀,Vue 3 内置) | 强制使用(深度集成) |
| 单元测试 | Jest + React Testing Library | Vitest + Vue Test Utils | Jasmine + TestBed(官方集成) |
| 学习曲线 | 低(JS 基础即可),但生态选择多 | 低(API 简洁直观) | 中高(RxJS、DI、装饰器) |
| 代码量(认证系统) | 中等,需要手动组织 | 较少,语法糖多 | 较多,但结构一致性强 |
决定性的选择建议
- 选 React:团队熟悉 JS/TS,追求灵活性和最大的生态(如想要任何状态管理库、任何路由方案)。
- 选 Vue:团队小型或快速原型,追求开发效率和直观性,Vue 的响应式 + Pinia 在认证这类“实时状态”场景中写起来最愉悦。
- 选 Angular:大型企业级项目,需要强类型约束、HTTP 拦截器、路由 Guard 等“开箱即用”的规范,团队需要长期维护,Angular 的架构一致性最佳。
最终的结论:如果只看“用户认证”这个具体案例的实现优雅度,Vue 3 + Pinia 由于其响应式自动追踪和 Pinia 的简洁性,代码最为清爽;Angular 因其强有力的拦截器和 Guard 类的分离,最适合需要严格工程规范的团队;React 则提供了最大的组合自由,但也需要自己搭建更多的脚手架。