You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React报错:useNavigate()仅可在<Router>组件上下文使用及权限控制问题

解决useNavigate上下文报错与实现正确的React路由权限控制

问题根源

你遇到的useNavigate() may be used only in the context of a <Router> component报错,是因为useAuthentication Hook在<Router>组件渲染前就被调用了(App组件顶层调用),此时useNavigate无法获取到路由上下文。另外,原写法中即使未登录,受保护页面组件(如JobPage)仍会被初始化,导致后端数据请求提前触发。

解决方案

1. 创建路由守卫组件ProtectedRoute

这个组件会在路由层面拦截未登录请求,只有认证通过时才渲染目标页面,避免未登录时加载页面组件。

// components/ProtectedRoute.js
import { Navigate } from 'react-router-dom';
import useAuthentication from '../utilities/useAuthentication';

const ProtectedRoute = ({ children }) => {
  const { isLoggedIn, isLoading } = useAuthentication();

  // 认证请求未完成时显示加载状态
  if (isLoading) {
    return <div>验证身份中...</div>;
  }

  // 已登录则渲染目标页面,否则跳转登录页
  return isLoggedIn ? children : <Navigate to="/login" replace />;
};

export default ProtectedRoute;

2. 修改useAuthentication Hook

移除useNavigate,让Hook专注于管理认证状态,添加加载状态处理异步请求过程:

// utilities/useAuthentication.js
import { useState, useEffect } from 'react';

const useAuthentication = () => {
  const [isLoggedIn, setIsLoggedIn] = useState(false);
  const [userData, setUserData] = useState(null);
  const [isLoading, setIsLoading] = useState(true);

  useEffect(() => {
    const checkLoginStatus = async () => {
      try {
        const response = await fetch('http://localhost:5000/api/check-auth', {
          method: 'GET',
          credentials: 'include',
        });
        if (response.ok) {
          const { userData } = await response.json();
          setIsLoggedIn(true);
          setUserData(userData);
        } else {
          setIsLoggedIn(false);
        }
      } catch (error) {
        console.error('认证检查失败:', error);
        setIsLoggedIn(false);
      } finally {
        setIsLoading(false);
      }
    };

    checkLoginStatus();
  }, []);

  return { isLoggedIn, userData, isLoading };
};

export default useAuthentication;

3. 重构App.js路由配置

用ProtectedRoute包裹所有需要权限的页面:

// App.js
import React from 'react';
import {
  BrowserRouter as Router,
  Route,
  Routes,
} from 'react-router-dom';
import CustomNavbar from './components/common/Navbar';
import HomePage from './pages/HomePage';
import LoginPage from './pages/LoginPage';
import RegisterPage from './pages/RegisterPage';
import CreateJobPage from './pages/CreateJobPage';
import JobsPage from './pages/JobsPage';
import JobPage from './pages/JobPage';
import DashboardPage from './pages/DashboardPage';
import ProtectedRoute from './components/ProtectedRoute';

function App() {
  return (
    <Router>
      <CustomNavbar />
      <Routes>
        <Route path="/" element={<HomePage />} />
        <Route path="/login" element={<LoginPage />} />
        <Route path="/register" element={<RegisterPage />} />
        <Route path="/create-job" element={<CreateJobPage />} />
        <Route path="/jobs" element={<JobsPage />} />
        {/* 受保护页面用ProtectedRoute包裹 */}
        <Route 
          path="/job/:id" 
          element={
            <ProtectedRoute>
              <JobPage />
            </ProtectedRoute>
          } 
        />
        <Route 
          path="/dashboard" 
          element={
            <ProtectedRoute>
              <DashboardPage />
            </ProtectedRoute>
          } 
        />
      </Routes>
    </Router>
  );
}

export default App;

为什么这样有效

  • ProtectedRoute在<Router>内部渲染,调用useAuthentication时已处于路由上下文,彻底解决useNavigate报错。
  • 只有登录状态验证通过后,才会渲染受保护页面组件,避免未登录时触发后端数据请求。
  • 添加isLoading状态,避免在认证请求过程中出现页面闪烁或错误状态。

内容的提问来源于stack exchange,提问作者Jordan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 19:07:09