React Router V4 - 组件未在 <Switch> 下呈现
React Router V4 - Components not rendering under <Switch>
我正在尝试将硬编码的 <Route />
块转换为从配置变量动态生成的内容。例如
来自
<Router>
<Switch>
<Route path="/" component={Home} exact />
<Route path="/about" component={About} />
<Route path="/documents" component={Documents} exact />
<Route path="/documents/faq" component={DocFAQ} />
<Route path="/documents/translations" component={Translations} />
</Switch>
</Router>
到
const routes = [
{
path: '/',
component: Home,
exact: true
},
{
path: '/about',
component: About
},
{
path: '/documents',
component: Documents,
children: [
{
path: '/faq',
component: DocFAQ
},
{
path: '/translations',
component: Translations
}
]
}
];
const RecursiveRoute = ({ route, parentPath = '' }) => {
const path = parentPath + route.path;
return (
<React.Fragment>
<Route path={path} exact={route.exact || (route.children != null)} component={route.component} />
{route.children && route.children.map((childRoute, i) => <RecursiveRoute key={i} route={childRoute} parentPath={path} />)}
</React.Fragment>
);
};
const Routes = () => (
<Router>
<Switch>
{routes.map((route, i) => <RecursiveRoute key={i} route={route} />)}
</Switch>
</Router>
);
当我在 <Router>
之外进行映射调用时,这段代码生成的正是我想要的;例如。我可以验证它输出的代码与之前的硬编码块完全相同。然而,当它位于 <Switch>
内部时,只有 routes
数组中的第一条路线被映射——没有生成其他任何路线。将日志记录语句放在 <RecursiveRoute>
中证实了这一点。
为什么会这样,我该如何解决?
另一个奇怪的事情是,如果我将 <RecursiveRoute>
的 JSX 直接粘贴到 map
语句中,它就可以工作(除了在这种情况下我不能递归):
<Switch>
{routes.map((route, i) => <Route key={i} path={route.path} exact={route.exact || (route.children != null)} component={route.component} />)}
</Switch>
但是如果我把它外包给另一个组件,映射又会失败。
[编辑]解决方案:
基于,将<RecursiveRoute>
从组件更改为函数解决了这个问题:
function generateRecursiveRoute(route, parentPath = '') {
const path = parentPath + route.path;
const routeHasChildren = (route.children != null);
const baseHtml = <Route path={path} exact={route.exact || routeHasChildren} component={route.component} key={path} />;
return !routeHasChildren ?
baseHtml :
<React.Fragment key={path}>
{baseHtml}
{route.children.map((childRoute) => generateRecursiveRoute(childRoute, path))}
</React.Fragment>;
}
const Routes = () => (
<Router>
<Switch>
{routes.map((route) => generateRecursiveRoute(route))}
</Switch>
</Router>
);
Switch
是 implemented in such a way,您提供多个组件作为 children,它将渲染第一个组件的 component
并匹配 path
。因此,如果您提供路由以外的其他内容作为 child(没有 path
和 component
属性的内容),您需要确保在其中编写渲染逻辑。因为 Switch
不知道在这里做什么,因为它看不到与 child 关联的 component
或 render
道具。
因此,当您直接映射到 Route
时,它们可以正常工作,但是当您映射到 RecursiveRoute
时,它们就会失败。它上面没有 path
也没有 component
,对吧?
我已经稍微更新了你的代码,所以路由直接呈现为 children of Switch
:
// refactor of RecursiveRoute to
// use it as an utility function, not as component
const getRecursiveRoute = route => {
if (route.children) {
const RootComponent = route.component;
return (
<Route
key={route.path}
path={route.path}
render={props => {
return (
<React.Fragment>
{/* render the root matching component*/}
<RootComponent {...props} />
{/* render the subroutes */}
{/* TODO: consider having a Switch here too */}
{route.children.map(route =>
getRecursiveRoute({
...route,
path: props.match.url + route.path
})
)}
</React.Fragment>
);
}}
/>
);
}
return (
<Route
key={route.path}
path={route.path}
exact={route.exact || route.children != null}
component={route.component}
/>
);
};
const Routes = () => {
return (
<Router>
<Switch>{routes.map(route => getRecursiveRoute(route))}</Switch>
</Router>
);
};
您可能需要修复一些关于精确路由的边缘情况。希望对你有帮助。
我正在尝试将硬编码的 <Route />
块转换为从配置变量动态生成的内容。例如
来自
<Router>
<Switch>
<Route path="/" component={Home} exact />
<Route path="/about" component={About} />
<Route path="/documents" component={Documents} exact />
<Route path="/documents/faq" component={DocFAQ} />
<Route path="/documents/translations" component={Translations} />
</Switch>
</Router>
到
const routes = [
{
path: '/',
component: Home,
exact: true
},
{
path: '/about',
component: About
},
{
path: '/documents',
component: Documents,
children: [
{
path: '/faq',
component: DocFAQ
},
{
path: '/translations',
component: Translations
}
]
}
];
const RecursiveRoute = ({ route, parentPath = '' }) => {
const path = parentPath + route.path;
return (
<React.Fragment>
<Route path={path} exact={route.exact || (route.children != null)} component={route.component} />
{route.children && route.children.map((childRoute, i) => <RecursiveRoute key={i} route={childRoute} parentPath={path} />)}
</React.Fragment>
);
};
const Routes = () => (
<Router>
<Switch>
{routes.map((route, i) => <RecursiveRoute key={i} route={route} />)}
</Switch>
</Router>
);
当我在 <Router>
之外进行映射调用时,这段代码生成的正是我想要的;例如。我可以验证它输出的代码与之前的硬编码块完全相同。然而,当它位于 <Switch>
内部时,只有 routes
数组中的第一条路线被映射——没有生成其他任何路线。将日志记录语句放在 <RecursiveRoute>
中证实了这一点。
为什么会这样,我该如何解决?
另一个奇怪的事情是,如果我将 <RecursiveRoute>
的 JSX 直接粘贴到 map
语句中,它就可以工作(除了在这种情况下我不能递归):
<Switch>
{routes.map((route, i) => <Route key={i} path={route.path} exact={route.exact || (route.children != null)} component={route.component} />)}
</Switch>
但是如果我把它外包给另一个组件,映射又会失败。
[编辑]解决方案:
基于<RecursiveRoute>
从组件更改为函数解决了这个问题:
function generateRecursiveRoute(route, parentPath = '') {
const path = parentPath + route.path;
const routeHasChildren = (route.children != null);
const baseHtml = <Route path={path} exact={route.exact || routeHasChildren} component={route.component} key={path} />;
return !routeHasChildren ?
baseHtml :
<React.Fragment key={path}>
{baseHtml}
{route.children.map((childRoute) => generateRecursiveRoute(childRoute, path))}
</React.Fragment>;
}
const Routes = () => (
<Router>
<Switch>
{routes.map((route) => generateRecursiveRoute(route))}
</Switch>
</Router>
);
Switch
是 implemented in such a way,您提供多个组件作为 children,它将渲染第一个组件的 component
并匹配 path
。因此,如果您提供路由以外的其他内容作为 child(没有 path
和 component
属性的内容),您需要确保在其中编写渲染逻辑。因为 Switch
不知道在这里做什么,因为它看不到与 child 关联的 component
或 render
道具。
因此,当您直接映射到 Route
时,它们可以正常工作,但是当您映射到 RecursiveRoute
时,它们就会失败。它上面没有 path
也没有 component
,对吧?
我已经稍微更新了你的代码,所以路由直接呈现为 children of Switch
:
// refactor of RecursiveRoute to
// use it as an utility function, not as component
const getRecursiveRoute = route => {
if (route.children) {
const RootComponent = route.component;
return (
<Route
key={route.path}
path={route.path}
render={props => {
return (
<React.Fragment>
{/* render the root matching component*/}
<RootComponent {...props} />
{/* render the subroutes */}
{/* TODO: consider having a Switch here too */}
{route.children.map(route =>
getRecursiveRoute({
...route,
path: props.match.url + route.path
})
)}
</React.Fragment>
);
}}
/>
);
}
return (
<Route
key={route.path}
path={route.path}
exact={route.exact || route.children != null}
component={route.component}
/>
);
};
const Routes = () => {
return (
<Router>
<Switch>{routes.map(route => getRecursiveRoute(route))}</Switch>
</Router>
);
};
您可能需要修复一些关于精确路由的边缘情况。希望对你有帮助。