React Router V4 - компоненты не рендерится под <Switch> - PullRequest
0 голосов
/ 15 февраля 2019

Я пытаюсь превратить блок жестко закодированных <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>
);

1 Ответ

0 голосов
/ 15 февраля 2019

Switch - это , реализованный таким образом , что вы предоставляете несколько компонентов в качестве дочерних, и он будет отображать первый компонент component с соответствующим path.Поэтому, если вы предоставляете что-то иное, чем Route as child (то, что не имеет этих реквизитов path и component), вам нужно убедиться, что вы записали туда свою логику рендеринга.Потому что Switch не знает, что здесь делать, так как не видит component или render реквизита, связанного с этим ребенком.

Итак, когда вы отображали на Route с, они работали напрямую, но когда вы отображали на RecursiveRoute, это не удавалось.На нем не было ни path, ни component, верно?

Я немного обновил ваш код, чтобы маршруты напрямую отображались как дочерние элементы 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>
  );
};

Edit x2kx286x44

Возможно, вам придется исправить некоторые крайние случаи о точной маршрутизации.Надеюсь, это поможет.

...