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

如何在独立NPM组件中定义React Router v6路由并集成?

React Router v6 复用路由组件问题解决方案

问题场景

我们的应用拥有自定义路由与组件(如Home、About Us等),同时引入了名为Basket的内部NPM包。该Basket组件包含多步流程(如用户信息填写、支付等),计划使用React Router v6处理各步骤间的导航。

查阅文档与社区资料后,标准实现方式如下:

<BrowserRouter>
  <Routes>
    <Route path="/" element={<Home />} />
    <Route path="/basket">
      <Route path="/user-details" element={<PaymentDetails />} />
    </Route>
  </Routes>
</BrowserRouter>

但由于Basket需在多个应用中复用,且维护仅需执行npm install package@latest,无法采用上述写法。

问题

以下写法无法运行并报错,该如何实现需求?

[Basket] is not a <Route> component. All component children of <Routes> must be a <Route> or <React.Fragment>

错误写法示例:

<BrowserRouter>
  <Routes>
    <Route path="/" element={<Home />} />
    <Basket countryCode="GB" />    
  </Routes>
</BrowserRouter>

Basket组件代码:

export const Basket = ({
  countryCode,
}: BasketProps) => (
  // 尝试过将下方代码作为Route或Fragment,均触发上述错误
  <Route path="/basket">
    <Route
      path="/mobile-capture"
      element={<UserDetails countryCode={countryCode} />}
    />
    // ... 其他组件
  </Route>
);

补充说明

目前仅能通过以下方式运行,但存在诸多不妥(如多<Routes />写法无官方文档支持):

<BrowserRouter>
  <Routes>
    <Route path="/" element={<Home />} />
  </Routes>
  <Routes>
    <Basket countryCode="GB" />    
  </Routes>
</BrowserRouter>

对应的Basket组件:

export const Basket = ({
  countryCode,
}: BasketProps) => (
  <Routes>
    <Route
      path="/user-details-capture"
      element={<UserDetails countryCode={countryCode} />}
    />
    // ... 其他组件
  </Routes>
);

解决方案

React Router v6明确要求<Routes>的子节点必须是<Route>或<React.Fragment>,因此不能直接将Basket组件放在<Routes>内部。以下是几种符合官方规范的可复用实现方式:

方式1:让Basket导出路由配置数组

修改Basket组件,返回路由对象数组,主应用中直接展开使用:

// Basket包中导出路由配置
export const getBasketRoutes = (countryCode) => [
  {
    path: "/basket",
    children: [
      { path: "mobile-capture", element: <UserDetails countryCode={countryCode} /> },
      // ... 其他路由配置
    ]
  }
];

主应用中使用:

<BrowserRouter>
  <Routes>
    <Route path="/" element={<Home />} />
    {/* 展开Basket的路由配置 */}
    {getBasketRoutes("GB").map((route, index) => (
      <Route key={index} path={route.path}>
        {route.children.map((child, idx) => (
          <Route key={idx} path={child.path} element={child.element} />
        ))}
      </Route>
    ))}
  </Routes>
</BrowserRouter>

方式2:用Outlet实现嵌套路由

将Basket作为父路由的布局组件,内部用<Outlet>渲染子路由,同时导出子路由配置供主应用注册:

// Basket包中代码
import { Outlet } from 'react-router-dom';

export const Basket = () => {
  return (
    <div className="basket-layout">
      {/* 这里可以放Basket的公共UI,比如步骤导航栏 */}
      <Outlet />
    </div>
  );
};

export const basketChildRoutes = (countryCode) => [
  { path: "mobile-capture", element: <UserDetails countryCode={countryCode} /> },
  // ... 其他子路由
];

主应用中使用:

import { Basket, basketChildRoutes } from 'your-basket-package';

<BrowserRouter>
  <Routes>
    <Route path="/" element={<Home />} />
    <Route path="/basket" element={<Basket />}>
      {/* 注册Basket的子路由 */}
      {basketChildRoutes("GB").map((route, index) => (
        <Route key={index} path={route.path} element={route.element} />
      ))}
    </Route>
  </Routes>
</BrowserRouter>

方式3:用createRoutesFromElements转换路由元素

在Basket中封装路由元素,通过createRoutesFromElements转换成路由对象,主应用中通过useRoutes使用:

// Basket包中代码
import { createRoutesFromElements, Route } from 'react-router-dom';

export const getBasketRouteElements = (countryCode) => createRoutesFromElements(
  <Route path="/basket">
    <Route path="mobile-capture" element={<UserDetails countryCode={countryCode} />} />
    {/* ... 其他路由 */}
  </Route>
);

主应用中使用:

import { useRoutes } from 'react-router-dom';

function App() {
  const routes = useRoutes([
    { path: "/", element: <Home /> },
    ...getBasketRouteElements("GB"),
  ]);
  return routes;
}

<BrowserRouter>
  <App />
</BrowserRouter>

以上方式均符合React Router v6官方规范,既保证了Basket组件的可复用性,又避免了非标准写法带来的潜在问题,后续维护只需更新NPM包即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 19:45:33