useNavigate() 只能在 <Router> 组件的上下文中使用

kid*_*kid 76 reactjs jestjs react-router react-router-dom react-hooks

请参阅下面的我的代码。我正在尝试添加此按钮,使用它返回上一页,react-router-dom但出现以下错误,并且网站上的所有组件都消失了。

错误:

useNavigate() 只能在组件上下文中使用

我的代码:

function App() {
  const navigate = useNavigate();
  return (
    <BrowserRouter>
      <div>
      <button onClick={() => navigate(-1)}>go back</button>
        <Nav/>
        <Routes>
          <Route exact path="/" element={<Home/>}/>
          <Route exact path="/home" element={<Home/>}/>
          <Route exact path="/upcoming/:user" element={<Upcoming/>}/>
          <Route exact path="/record/:user" element={<Record/>}/>
          <Route path="*" element={<NotFound/>}/>
        </Routes>
      </div>
    </BrowserRouter>
  );
}
Run Code Online (Sandbox Code Playgroud)

这是我在控制台中收到的错误:

错误

sli*_*wp2 107

此错误会在useNavigate中引发。useInRouterContext将检查组件(使用useNavigate钩子)是否是<Router>. 如果该组件不是组件的后代<Router>,则会抛出此错误

下面的源代码解释了为什么不能在组件之外使用useNavigate, :useLocationRouter

useNavigate在底层使用useLocation时,将从LocationContext提供程序useLocation获取位置。如果您想获取反应上下文,则应该将该组件呈现为上下文提供者的后代。 组件使用LocationContext.ProviderNavigationContext.Provider。这就是为什么您需要将组件渲染为孩子,以便钩子可以从提供者获取上下文数据。RouteruseNavigateNavigationContextLocationContext

您的环境是浏览器,因此您需要使用BrowserRouter. BrowserRouter是基于Router.

重构为:

App.jsx:

function App() {
  const navigate = useNavigate();
  return (
      <div>
        <button onClick={() => navigate(-1)}>go back</button>
        <Nav/>
        <Routes>
          <Route exact path="/" element={<Home/>}/>
          <Route exact path="/home" element={<Home/>}/>
          <Route exact path="/upcoming/:user" element={<Upcoming/>}/>
          <Route exact path="/record/:user" element={<Record/>}/>
          <Route path="*" element={<NotFound/>}/>
        </Routes>
      </div>
  );
}
Run Code Online (Sandbox Code Playgroud)

index.jsx:

import ReactDOM from 'react-dom';
import { BrowserRouter } from 'react-router-dom';
import App from './App';

ReactDOM.render(
  <BrowserRouter>
    <App/>
  </BrowserRouter>,
  document.getElementById('root')
)
Run Code Online (Sandbox Code Playgroud)


小智 27

我也遇到了同样的问题,但是测试了一个带有钩子的组件useNavigate。通过将我的组件包装在RoutewithRoutes和中解决了这个问题BrowserRouter。希望这可以帮助其他有同样错误的人。

let container = null;
    beforeEach(() => {
    container = document.createElement("div");
    document.body.appendChild(container);
});

afterEach(() => {
    // cleanup on exiting
    unmountComponentAtNode(container);
    container.remove();
    container = null;
});

test('finds qualified insurrance policies', () => {
    act(() => {
    render(
    <BrowserRouter>
        <Routes>   
            <Route path="*" element= {<QuaifiedPolicies policyTypes={false} />}/>
        </Routes>
    </BrowserRouter>
        , container);
    });
    expect(screen.getByLabelText('some text'))
});
Run Code Online (Sandbox Code Playgroud)

  • 您不需要将其设为路由,只需用 BrowserRouter 包装它即可解决问题 (15认同)

bre*_*nse 23

供将来参考:也可能会出现此错误

  • 如果您导入<Router>react-router-dom并导入useNavigatereact-router
  • 如果您useNavigate不同版本的软件包导入等BrowserRouter,例如 v5 和 v6


Rah*_*rma 16

您正在使用外部BrowserRouter提供商的钩子。这就是你收到错误的原因。像下面这样重构你的组件来解决这个问题:

function Root() {
  const navigate = useNavigate();
  return (
    <div>
      <button onClick={() => navigate(-1)}>go back</button>
      <Nav />
      <Routes>
        <Route exact path="/" element={<Home />} />
        <Route exact path="/home" element={<Home />} />
        <Route exact path="/upcoming/:user" element={<Upcoming />} />
        <Route exact path="/record/:user" element={<Record />} />
        <Route path="*" element={<NotFound />} />
      </Routes>
    </div>
  );
}

function App() {
  return (
    <BrowserRouter>
      <Root />
    </BrowserRouter>
  );
}
Run Code Online (Sandbox Code Playgroud)