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

React Router中useLocation上下文错误及全局组件实现方案咨询

解决useLocation必须在Router上下文使用的问题

问题原因

useLocation 钩子依赖React Router提供的上下文,当前EDProgressBar组件被放在RouterProvider外部,不在上下文范围内,因此抛出错误:

Uncaught Error: useLocation() may be used only in the context of a component.

同时需求要求EDProgressBar全局存在,不受路由切换影响,而RouterProvider不支持直接传入子组件。

解决方案:创建全局根布局

通过创建根布局组件,将全局UI组件(包括EDProgressBar)放入路由上下文,同时保留全局显示的特性。

步骤1:创建根布局组件

新建根布局文件(比如@/layouts/RootLayout.tsx),将全局组件和路由出口Outlet组合:

import React from 'react';
import { Outlet } from 'react-router-dom';
import EDNotification from '@/ui/EDNotification';
import EDProgressBar from '@/ui/EDProgressBar';

const RootLayout: React.FC = () => {
  return (
    <>
      {/* Outlet用于渲染当前匹配的路由页面内容 */}
      <Outlet />
      <div id="backdrop-root" />
      <div id="overlay-root" />
      <EDNotification />
      <EDProgressBar />
    </>
  );
};

export default RootLayout;

步骤2:修改路由构建器

更新RouterBuilder,将所有路由作为根布局的子路由,确保全局组件处于Router上下文内:

import React from 'react';
import { type RouteObject } from 'react-router-dom';
import RootLayout from '@/layouts/RootLayout'; // 导入根布局

const CliAuth = React.lazy(() => import('./pages/CliAuth'));
const CliAuthenticated = React.lazy(() => import('./pages/CliAuthenticated'));
const NotFound = React.lazy(() => import('./pages/NotFound'));

const RouterBuilder = (isAuthenticated: boolean | null) => {
    const generalRoutes: RouteObject[] = [
        {
            path: 'cli-auth',
            element: <CliAuth />,
        },
        {
            path: 'cli-authenticated',
            element: <CliAuthenticated />,
        },
        {
            path: 'not-found',
            element: <NotFound />,
        },
        {
            path: '*',
            element: isAuthenticated === null ? null : <NotFound />,
        },
    ];

    // 将所有路由包裹在根布局下
    return [
        {
            path: '/',
            element: <RootLayout />,
            children: [...(isAuthenticated ? authorizedRoutes : unAuthorizedRoutes), ...generalRoutes],
        },
    ];
};

export default RouterBuilder;

步骤3:简化AppView组件

移除AppView中原来的全局组件引用,因为它们已经被移入根布局:

import React, { Suspense, useMemo } from 'react';
import { RouterProvider, createBrowserRouter } from 'react-router-dom';
import RouterBuilder from './App.router';

interface IProps {
    readonly isAuthenticated: boolean | null;
}

const AppView: React.FC<IProps> = (props: React.PropsWithChildren<IProps>) => {
    const routes = useMemo(() => {
        return RouterBuilder(props.isAuthenticated);
    }, [props.isAuthenticated]);

    return (
        <Suspense fallback={null}>
            <RouterProvider router={createBrowserRouter(routes)} fallbackElement={null} />
        </Suspense>
    );
};

AppView.displayName = 'AppView';
AppView.defaultProps = {};

export default React.memo(AppView);

效果说明

修改后:

  • EDProgressBar处于Router上下文内,可正常使用useLocation监听路由变化
  • 根布局全局生效,EDProgressBar会始终显示在页面上,不受具体路由组件的影响
  • 符合React Router v6的路由嵌套设计规范

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 23:18:33