简体   繁体   English

路线只能用作的孩子<routes>元素,在 React 路由器 v6 中</routes>

[英]A Route is only ever to be used as the child of <Routes> element, in React router v6

I am struggling to render my routes list with React router v6.我正在努力使用 React router v6 呈现我的路由列表。 I have already read the docs and I am aware of a new structure of routing, but currently having a problem rendering list (nested) of routes.我已经阅读了文档并且我知道一种新的路由结构,但目前在呈现路由列表(嵌套)时遇到问题。

export default [{
  path: '/',
  element: Root,
  routes: [{
    path: REGISTER,
    element: Register,
    isProtected: true,
  }],
}];

export const RouteMatcher = ({ routes }) => {
  return routes.map((route, index) => {
    if (route.element) {
      return (
        <Route key={index} path={route.path} element={<route.element />}>
          {route.routes ? (
            <Route path={route.path} element={<RouteMatcher routes={route.routes} />
          ) : null}
        </Route>
      );
    }

    return null;
  });
};

<BrowserRouter>
  <Routes>
    <Route path="/" element={<RouteMatcher routes={routes} />} />
  </Routes>
</BrowserRouter>

It's not obvious to me what's going on here even though the error message has a clear explanation of the issue.尽管错误消息对问题有明确的解释,但对我来说这里发生的事情并不明显。 Even I try this way it doesn't work.即使我尝试这种方式它也不起作用。

 <BrowserRouter>
      <Routes>
        <Route path="/">
          {routes.map((route, index) => {
            if (route.element) {
              return (
                <Route key={index} path={route.path} element={<route.element />}>
                  {route.routes ? (
                    <Route path={route.path} element={<RouteMatcher routes={route.routes} indexPathname={indexPathname} />} />
                  ) : null}
                </Route>
              );
            }

            return null;
          })}
        </Route>
      </Routes>
    </BrowserRouter>

As you can see Route is always a child of Routes or Route (when nested).如您所见, Route始终是RoutesRoute (嵌套时)的子项。

** UPDATED ** Here is the react router v5 implementation ** 更新 ** 这里是 react router v5 实现

<Provider store={store}>
   <GlobalStyles />
   <AppContentWrapper>
       <RouteHandler />
   </AppContentWrapper>
</Provider>

Route handler component路由处理程序组件

<BrowserRouter>
   {generateRouteMatches(
       routes,
       indexPathname,
       auth.isLoading,
       auth.isLoggedIn
    )}
</BrowserRouter>

Route generator component路由生成器组件

export const generateRouteMatches = (
  baseRoutes: IAppRoute[],
  indexPathname: string,
  userPermissions: PermissionShape[],
  isLoading: boolean,
  isLoggedIn: boolean,
) => {
  AccessControl.createPermissions(userPermissions);

  return baseRoutes.map((route) => (
    <MatchRoutes
      indexPathname={indexPathname}
      authIsLoading={isLoading}
      isLoggedIn={isLoggedIn}
      key={route.path}
      {...route}
    />
  ));
};

MatchRoutes component with RouteRenderer MatchRoutes 组件与 RouteRenderer

function MatchRoutes({ location, ...route }: any) {
  const routePermissions = AccessControl.getPermissions(route.zone);

  if (!routePermissions.canRead && route.isProtectedRoute) {
    return <Route {...omit(route, ['component'])} component={() => {
      return <div className="centerXY">You dont have permissions to view this page</div>;
    }} />;
  }

  return (
    <Route {...omit(route, ['component'])} render={(props) => (
      <RouteRenderer {...props} route={route} location={location} />
    )} />
  );
}

function RouteRenderer({ route, ...props }: any) {
  const location = useLocation();

  if (location?.pathname === '/') {
    return (
      <Redirect
        to={{
          pathname: route.indexPathname,
          state: { from: location },
        }}
      />
    );
  }

  if (route.isProtectedRoute && !route.isLoggedIn && !route.authIsLoading) {
    return (
      <Redirect to={{
        pathname: '/login',
        state: { from: location },
      }}/>
    );
  }

  if (route.component) {
    return (
      <route.component
        {...props}
        params={props.match.params}
        routes={route.routes}
      >
        {route.routes
          ? route.routes.map((cRoute, idx) => (
            <MatchRoutes
              authIsLoading={route.authIsLoading}
              isLoggedIn={route.isLoggedIn}
              key={idx}
              {...cRoute}
            />
          ))
          : null
        }
      </route.component>
    );
  } else if (route.routes) {
    return (
      <>
        {route.routes.map((cRoute, idx) => (
          <MatchRoutes
            authIsLoading={route.authIsLoading}
            isLoggedIn={route.isLoggedIn}
            key={idx}
            {...cRoute}
          />
        ))}
      </>
    );
  } else {
    return null;
  }

}

export default MatchRoutes;

In the first example the RouteMatcher component is rendering a Route component directly.在第一个示例中, RouteMatcher组件直接渲染Route组件。 The mapped routes it is rendering need to be wrapped in a Routes component.它正在渲染的映射路由需要包装在Routes组件中。

export const RouteMatcher = ({ routes }) => {
  return (
    <Routes>
      {routes
        .filter(route => route.element)
        .map((route, index) => {
          return (
            <Route
              key={index}
              path={route.path}
              element={<route.element />}
            >
              {route.routes && (
                <Route
                  path={route.path}
                  element={<RouteMatcher routes={route.routes} />}
                />
              )}
            </Route>
          );
        })
      }
    </Routes>
  );
};

I suspect something similar is occurring int he second code example as well.我怀疑第二个代码示例中也发生了类似的事情。

I suggest using a better formed routes configuration and use the useRoutes hook.我建议使用格式更好的路由配置并使用useRoutes挂钩。

Example:例子:

export default [{
  path: '/',
  element: <Root />,
  children: [
    {
      element: <AuthOutlet />,
      children: [
        {
          path: REGISTER,
          element: <Register />,
        },
        ... other routes to protect ...
      ],
      ... other unprotected routes ...
    },
  ],
}];

... ...

import appRoutes from '../path/to/routes';

...

const routes = useRoutes(appRoutes);

...

<BrowserRouter>
  {routes}
</BrowserRouter>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM