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

Switchimplemented in such a way,您提供多个组件作为 children,它将渲染第一个组件的 component 并匹配 path。因此,如果您提供路由以外的其他内容作为 child(没有 pathcomponent 属性的内容),您需要确保在其中编写渲染逻辑。因为 Switch 不知道在这里做什么,因为它看不到与 child 关联的 componentrender 道具。

因此,当您直接映射到 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>
  );
};

您可能需要修复一些关于精确路由的边缘情况。希望对你有帮助。