簡體   English   中英

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

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

我正在努力使用 React router v6 呈現我的路由列表。 我已經閱讀了文檔並且我知道一種新的路由結構,但目前在呈現路由列表(嵌套)時遇到問題。

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>

盡管錯誤消息對問題有明確的解釋,但對我來說這里發生的事情並不明顯。 即使我嘗試這種方式它也不起作用。

 <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>

如您所見, Route始終是RoutesRoute (嵌套時)的子項。

** 更新 ** 這里是 react router v5 實現

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

路由處理程序組件

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

路由生成器組件

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 組件與 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;

在第一個示例中, RouteMatcher組件直接渲染Route組件。 它正在渲染的映射路由需要包裝在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>
  );
};

我懷疑第二個代碼示例中也發生了類似的事情。

我建議使用格式更好的路由配置並使用useRoutes掛鈎。

例子:

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