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

ReactJS:在index层使用createBrowserRouter并保留App内路由

问题描述

使用useBlocker时抛出错误:Error: useBlocker must be used within a data router,需将BrowserRouter替换为createBrowserRouter,但希望路由配置仍保留在App.tsx中,如何修改?


原代码结构

index.tsx

import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import { BrowserRouter } from 'react-router-dom';
import { Provider as ReduxProvider } from "react-redux";

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <ReduxProvider store={store}>
    <BrowserRouter>
    <App />
    </BrowserRouter>
    </ReduxProvider>
  </React.StrictMode>
);

函数式App组件

import {Routes, Route} from "react-router-dom";
import About from "./component/About";
import Team from "./component/Team";
import Home from "./component/Home";

function App() {
  return (
    <>
    <Navbar />
    <Routes >
      <Route path="/" element={ <Home /> } />
      <Route path="/team" element={ <Team /> } />
      <Route path="/about" element={ <About /> } />
    </Routes>
    </>
  );
}

export default App;

withRouter Hook

import {
  Location,
  NavigateFunction,
  Params,
  useLocation,
  useNavigate,
  useParams,
} from "react-router-dom";

export interface RouterProps {
  location: Location;
  navigate: NavigateFunction;
  params: Params;
}

export interface WithRouter {
  router: RouterProps;
}

function withRouter(Component: any) {
  function ComponentWithRouterProp(props: any) {
    const location = useLocation();
    const navigate = useNavigate();
    const params = useParams();
    return <Component {...props} router={{ location, navigate, params }} />;
  }

  return ComponentWithRouterProp;
}

export default withRouter;

类组件App

class App extends React.Component<IProps, IState> {
  constructor(props: IProps) {
    super(props);
  }

  render() {
    return (
      <div className='container'>
        <Navbar />
        <Suspense>
        <Routes>
          <Route path="/" element={ <Home /> } />
          <Route path="/team" element={ <Team /> } />
          <Route path="/about" element={ <About /> } />
        </Routes>
        </Suspense>
      </div>
    );
  }
}

export default withRouter(App);

解决方案

函数式组件版本

步骤1:修改index.tsx

移除BrowserRouter,改用createBrowserRouter和RouterProvider,复用App中的路由配置:

import React from 'react';
import ReactDOM from 'react-dom/client';
import { createBrowserRouter, RouterProvider } from 'react-router-dom';
import App, { routes } from './App';
import { Provider as ReduxProvider } from "react-redux";

// 创建数据路由,将App作为父路由,子路由复用App中的配置
const router = createBrowserRouter([
  {
    path: "/",
    element: <App />,
    children: routes,
  },
]);

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <ReduxProvider store={store}>
      <RouterProvider router={router} />
    </ReduxProvider>
  </React.StrictMode>
);

步骤2:调整App.tsx

抽离路由配置为单独数组,用Outlet渲染子路由内容,保留原有布局结构:

import { Outlet, RouteObject } from "react-router-dom";
import About from "./component/About";
import Team from "./component/Team";
import Home from "./component/Home";

// 抽离路由配置,供index.tsx引用
export const routes: RouteObject[] = [
  { path: "/", element: <Home /> },
  { path: "/team", element: <Team /> },
  { path: "/about", element: <About /> },
];

function App() {
  return (
    <>
      <Navbar />
      {/* Outlet负责渲染子路由对应的组件 */}
      <Outlet />
    </>
  );
}

export default App;

类组件版本

步骤1:修改index.tsx

与函数式版本一致,替换为数据路由:

import React from 'react';
import ReactDOM from 'react-dom/client';
import { createBrowserRouter, RouterProvider } from 'react-router-dom';
import App, { routes } from './App';
import { Provider as ReduxProvider } from "react-redux";

const router = createBrowserRouter([
  {
    path: "/",
    element: <App />,
    children: routes,
  },
]);

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <ReduxProvider store={store}>
      <RouterProvider router={router} />
    </ReduxProvider>
  </React.StrictMode>
);

步骤2:调整类组件App.tsx

同样抽离路由配置,用Outlet替代原Routes组件:

import React, { Suspense } from 'react';
import { Outlet, RouteObject } from "react-router-dom";
import About from "./component/About";
import Team from "./component/Team";
import Home from "./component/Home";
import withRouter from './withRouter';

export const routes: RouteObject[] = [
  { path: "/", element: <Home /> },
  { path: "/team", element: <Team /> },
  { path: "/about", element: <About /> },
];

interface IProps {
  // 保留原有Props类型定义
}

interface IState {
  // 保留原有State类型定义
}

class App extends React.Component<IProps, IState> {
  constructor(props: IProps) {
    super(props);
  }

  render() {
    return (
      <div className='container'>
        <Navbar />
        <Suspense fallback={<div>加载中...</div>}>
          {/* 使用Outlet渲染子路由内容 */}
          <Outlet />
        </Suspense>
      </div>
    );
  }
}

export default withRouter(App);

关键说明

  • useBlocker是React Router v6.4+数据路由专属API,必须配合createBrowserRouter和RouterProvider使用,无法与传统BrowserRouter兼容。
  • 通过Outlet组件可以在父路由组件中渲染子路由内容,既保留了App.tsx中的布局(Navbar),又能将路由配置集中在同一文件。
  • 类组件的withRouter无需修改,在数据路由环境下依然可以正常获取路由相关hooks的返回值。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 06:04:51