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

React路由重构问题:useNavigate在Router上下文外调用报错

React Router 导航逻辑重构报错修复方案

你遇到的报错 useNavigate() may be used only in the context of a <Router> component 是因为**useNavigate 钩子只能在被 <RouterProvider> 包裹的组件(即Router上下文内部)中调用**。你的App组件是渲染 <RouterProvider> 的父组件,不在Router上下文范围内,所以直接在App里调用 useNavigate 会触发错误。

以下是三种可行的修复方案,适配不同场景需求:

方案一:利用Router实例的navigate方法

createBrowserRouter 返回的router对象自带 navigate 方法,无需依赖 useNavigate 钩子,直接用它创建导航函数传给Sidebar即可。

修改后的App.js:

function App() {
    const router = createBrowserRouter([
        {
            path: "/",
            element: <Sidebar />,
            errorElement: <ErrorPage />,
            children: [
                {
                    path: "",
                    element: <Home />
                },
                {
                    path: "decks",
                    element: <Review />,
                },
            ],
        },
    ])

    // 基于router实例创建导航函数
    const routeToHome = () => router.navigate('/');
    const routeToDecks = () => router.navigate('/decks');

    // 更新路由配置中的Sidebar组件,传入导航函数
    router.routes[0].element = <Sidebar homeRoute={routeToHome} deckRoute={routeToDecks} />;

    return (
        <React.StrictMode>
            <RouterProvider router={router} />
        </React.StrictMode>
    );
}

export default App;

Sidebar.js保持你重构后的代码不变。

方案二:用Context全局共享导航逻辑(推荐中大型项目)

创建一个导航上下文,把导航函数封装在Router上下文内的组件中,所有需要导航的组件都可以通过自定义Hook获取,复用性更强。

  1. 创建 NavigationContext.js:
import { createContext, useContext, useNavigate } from 'react-router-dom';

const NavigationContext = createContext();

export function NavigationProvider({ children }) {
    const navigate = useNavigate();

    const navigationActions = {
        routeToHome: () => navigate('/'),
        routeToDecks: () => navigate('/decks'),
    };

    return (
        <NavigationContext.Provider value={navigationActions}>
            {children}
        </NavigationContext.Provider>
    );
}

export function useNavigation() {
    return useContext(NavigationContext);
}
  1. 修改App.js,将NavigationProvider作为路由根组件的子组件:
import { NavigationProvider } from './NavigationContext';

function App() {
    const router = createBrowserRouter([
        {
            path: "/",
            element: (
                <NavigationProvider>
                    <Sidebar />
                </NavigationProvider>
            ),
            errorElement: <ErrorPage />,
            children: [
                {
                    path: "",
                    element: <Home />
                },
                {
                    path: "decks",
                    element: <Review />,
                },
            ],
        },
    ])

    return (
        <React.StrictMode>
            <RouterProvider router={router} />
        </React.StrictMode>
    );
}

export default App;
  1. 修改Sidebar.js,用自定义Hook获取导航函数:
import { useNavigation } from './NavigationContext';

const Sidebar = () => {
    const { routeToHome, routeToDecks } = useNavigation();
    
    return (
        <>
        <div className="sidebar-wrapper">
            <SidebarOption logo="🏠" title="Home" click={routeToHome} />
            <SidebarOption logo="🗂"  title="Decks" click={routeToDecks} />
        </div>
        <div id="detail">
            <Outlet />
        </div>
        </>
    )
}

export default Sidebar;

方案三:通过回调获取Sidebar内的导航函数

如果只需要在App中偶尔触发导航,可以让Sidebar在挂载时把内部的导航函数通过回调传给App。

修改后的Sidebar.js:

import { useNavigate, useEffect } from 'react-router-dom';

function Sidebar({ onNavigationReady }) {
    const navigate = useNavigate()
    
    const routeToHome = () => navigate('/');
    const routeToDecks = () => navigate('/decks');

    // 组件挂载时传递导航函数给App
    useEffect(() => {
        onNavigationReady({ routeToHome, routeToDecks });
    }, [onNavigationReady]);
    
    return (
        <>
        <div className="sidebar-wrapper">
            <SidebarOption logo="🏠" title="Home" click={routeToHome} />
            <SidebarOption logo="🗂"  title="Decks" click={routeToDecks} />
        </div>
        <div id="detail">
            <Outlet />
        </div>
        </>
    )
}

export default Sidebar;

修改后的App.js:

import { useRef } from 'react';

function App() {
    const navigationActions = useRef(null);

    // 接收Sidebar传递的导航函数
    const handleNavigationReady = (actions) => {
        navigationActions.current = actions;
    };

    // 示例:在App中触发导航
    const triggerDecksNavigation = () => {
        navigationActions.current?.routeToDecks();
    };

    const router = createBrowserRouter([
        {
            path: "/",
            element: <Sidebar onNavigationReady={handleNavigationReady} />,
            errorElement: <ErrorPage />,
            children: [
                {
                    path: "",
                    element: <Home />
                },
                {
                    path: "decks",
                    element: <Review />,
                },
            ],
        },
    ])

    return (
        <React.StrictMode>
            <RouterProvider router={router} />
            {/* 可以添加按钮调用triggerDecksNavigation */}
            {/* <button onClick={triggerDecksNavigation}>Go to Decks from App</button> */}
        </React.StrictMode>
    );
}

export default App;

方案选择建议

  • 简单场景选方案一,实现快速,代码改动少;
  • 中大型项目选方案二,全局共享导航逻辑,易于维护和扩展;
  • 需要在App(RouterProvider父组件)中触发导航选方案三。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 13:20:28