[英]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
始终是Routes
或Route
(嵌套时)的子项。
** 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.