要真正避免路由状态污染,需解耦错误拦截、状态隔离和路由决策:区分网络异常与业务错误,用loading/error/data三态控制渲染,守卫组件采用pending/authenticated/unauthenticated三值状态,并通过safeRequest封装统一错误处理。

直接用 try-catch 包裹异步调用本身不能隔离路由状态,关键在于它只控制**当前执行上下文的错误传播路径**,而 React Router 的路由跳转(如 <navigate></navigate> 或 useNavigate)是副作用操作,一旦触发就会改变 URL 和渲染树。所谓“污染”,本质是错误导致跳转逻辑误判或状态错乱。要真正避免,得把错误拦截、状态隔离和路由决策三者解耦。
明确错误发生位置,不混用网络层与业务层判断
很多“路由状态被污染”其实源于没区分两类错误:fetch 失败(如网络中断)属于 JS 异常,会被 catch 捕获;但后端返回 { code: 403, msg: "无权限" } 这类响应,不是异常,await fetch() 会正常完成,后续 if 判断必须显式处理。若漏掉这层校验,组件可能基于错误数据执行跳转,比如把 403 当作登录态有效,进而跳进受保护页面再崩溃。
- fetch 成功但 status 非 2xx → 触发业务错误,走自定义提示,不跳转
- fetch 报 TypeError(如跨域、离线)→ 真异常,catch 捕获,可统一降级到维护页
- 解析 JSON 失败或 data.code !== 0 → 业务约定错误,需在 try 块内主动 throw,确保进入 catch 分支
用 loading + error + data 三态隔离渲染逻辑
动态路由组件(如 /user/:id)不应在初始 render 就决定跳转,而应先展示加载态,等数据确认后再决策。错误不能让组件“静默失败”,必须有明确状态出口。
开箱即用的技能链路由引擎。13 条预定义链覆盖搜索、开发、审查、MLOps、法律、创意等场景,三层路由架构(触发词→SAD反馈→DAG编排),recall@10=96.97%。配置驱动(chains.yaml),零代码扩展。pip install skill-weave-chains 一键安装。
- 初始化时设
const [state, setState] = useState({ loading: true, error: null, data: null }) - try 块里获取并校验数据,成功则
setState({ loading: false, data }),失败则setState({ loading: false, error: err.message }) - render 中按 state 分支:loading 显示骨架屏;error 显示重试按钮(不跳转);data 才渲染真实内容或条件跳转
路由守卫中引入 pending 状态,阻断竞态跳转
在 ProtectedRoute 这类守卫组件里,初始 isAuth = false 是危险的——它会让未认证状态立即触发重定向,掩盖了“正在验证”的中间过程。必须用三值状态替代布尔值。
- 状态定义:
const [authStatus, setAuthStatus] = useState('pending')('pending'/'authenticated'/'unauthenticated') - useEffect 内发起认证请求,成功设为 'authenticated',失败设为 'unauthenticated',pending 期间不渲染任何子组件也不跳转
- 只有 authStatus === 'authenticated' 时才 return children;其他情况返回空占位或全局 loading,彻底避免“闪跳”
高阶封装 safeRequest,让错误不逃出业务边界
把错误处理收口到请求层,比每个组件写 try-catch 更可靠。safeRequest 返回 Promise,调用方只需关注成功数据,所有错误(网络+业务)都由它统一抛出,你可以在顶层用 ErrorBoundary 捕获,或在路由 loader 中集中处理。
- 封装时传函数而非执行结果:
safeRequest(() => fetch('/api/profile')),防止立即执行无法拦截 - HTTP 层校验(
!res.ok)和业务层校验(data.code !== 0)都放在 try 内,确保全部纳入错误边界 - catch 中不吞错误,而是
throw new AuthError(...)或throw new NetworkError(...),便于上层按类型分流(比如 AuthError 触发登出,NetworkError 显示重试)


















