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

React Router useNavigate报错:需在<Router>上下文使用的解决求助

问题原因

你在App组件的顶层直接调用了useNavigate()钩子,但<BrowserRouter>是在App组件的return语句中才渲染的。这意味着当App组件初始化时,<Router>的上下文还不存在,所以useNavigate()无法获取到路由上下文,从而抛出错误。

解决方案

有两种简单的修复方式:

方式一:将首页表单抽为独立组件

把根路径的表单逻辑抽成一个单独的组件,在这个组件内部调用useNavigate(),这样组件就处于<Router>的上下文范围内了:

// Home.jsx
import React, { useState } from 'react';
import { useNavigate } from 'react-router-dom';
import axios from 'axios';

export default function Home() {
  const [destination, setDestination] = useState('');
  const navigate = useNavigate();

  const handleSubmit = async (e) => {
    e.preventDefault();
    const data = { destination };
    await axios.post('/travel', data);
    navigate("/travelplan");
  };

  return (
    <div>
      <form onSubmit={handleSubmit} style={{ textAlign: "center" }}>
        <div>
          <label>
            Destination:
            <input
              type="text"
              value={destination}
              onChange={(e) => setDestination(e.target.value)}
            />
          </label>
        </div>
        <button type="submit">Submit</button>
      </form>
    </div>
  );
}

然后在App组件中引入并使用这个组件:

// App.jsx
import React, { useState } from 'react';
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import axios from 'axios';
import NavBar from './NavBar';
import Footer from './Footer';
import SignIn from './SignIn';
import SignUp from './SignUp';
import TravelPlan from './TravelPlan';
import Home from './Home'; // 引入新组件

function App() {
  const [loggedIn, setLoggedIn] = useState(false);

  return (
    <div>
      <BrowserRouter>
        <NavBar loggedIn={loggedIn} setLoggedIn={setLoggedIn} handleSignin={handleSignin} />
          <Routes>
            <Route path="/" element={<Home />} /> {/* 使用Home组件 */}
            <Route path="/signin" element={<SignIn handleSignin={handleSignin} />} />
            <Route path="/signup" element={<SignUp />} />
            <Route path="/travelplan" element={<TravelPlan />} />
          </Routes>
        <Footer />
      </BrowserRouter>
    </div >
  );
}

export default App;

方式二:将<BrowserRouter>移到App组件外部

修改index.js(或渲染App的入口文件),让<BrowserRouter>包裹整个App组件,这样App组件就处于路由上下文范围内了:

// index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import { BrowserRouter } from 'react-router-dom';
import App from './App';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <BrowserRouter>
    <App />
  </BrowserRouter>
);

然后修改App组件,移除内部的<BrowserRouter>:

// App.jsx
import React, { useState } from 'react';
import { Routes, Route, useNavigate } from 'react-router-dom';
import axios from 'axios';
import NavBar from './NavBar';
import Footer from './Footer';
import SignIn from './SignIn';
import SignUp from './SignUp';
import TravelPlan from './TravelPlan';

function App() {
  const [loggedIn, setLoggedIn] = useState(false);
  const navigate = useNavigate(); // 现在可以正常调用了

  const [destination, setDestination] = useState('');

  const handleSubmit = async (e) => {
    e.preventDefault();
    const data = { destination };
    await axios.post('/travel', data);
    navigate("/travelplan");
  };

  return (
    <div>
      <NavBar loggedIn={loggedIn} setLoggedIn={setLoggedIn} handleSignin={handleSignin} />
        <Routes>
          <Route path="/" element={
            <div>
              <form onSubmit={handleSubmit} style={{ textAlign: "center" }}>
                <div>
                  <label>
                    Destination:
                    <input
                      type="text"
                      value={destination}
                      onChange={(e) => setDestination(e.target.value)}
                    />
                  </label>
                </div>
                <button type="submit">Submit</button>
              </form>
            </div>
          }>
          </Route>
          <Route path="/signin" element={<SignIn handleSignin={handleSignin} />} />
          <Route path="/signup" element={<SignUp />} />
          <Route path="/travelplan" element={<TravelPlan />} />
        </Routes>
      <Footer />
    </div >
  );
}

export default App;
补充说明

两种方式都能解决问题,推荐第一种方式,因为它更符合组件拆分的原则,把路由相关的逻辑局限在对应的页面组件中,代码结构更清晰。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 02:17:42