React router v4 панировочные сухари

Я пытаюсь реализовать хлебные крошки React Router для v4

Ниже приведены мои маршруты:

    const routes = {
      '/': 'Home',
      '/page1': 'Page 1',
      '/page2': 'Page 2'
    };

Я мог бы поместить хлебные крошки, используя эту библиотеку в моем приложении, однако у меня возникают следующие вопросы:

Que. # 1:

Когда я нажимаю на Home в моих хлебных крошках я вижу изменения URL в http://localhost:8080 Тем не менее, браузер по-прежнему показывает ту же страницу, на которой я нахожусь.

Que. # 2:

Когда я перехожу к Page2 из Page1, url изменения от http://localhost:8080/page1 в http://localhost:8080/page2,

Таким образом, крошки показали изменения Home / Page 2 вместо того, чтобы меняться как Home / Page 1 / Page 2

Я знаю, что это может быть потому, что url просто имеет /page2 после имени хоста. Но могу ли я добиться отображения как: Home / Page 1 / Page 2?

Ниже код в моей главной App.jsx:

<Router>
  <div>
    <Link to="/"><div className="routerStyle"><Glyphicon glyph="home" /></div></Link>
    <Route exact path="/" component={LandingPage}/>
    <Route path="/page1" component={Page1}/>
    <Route path="/page2" component={Page2}/>
  </div>
</Router>

и если я использую, как показано ниже, для обслуживания панировочных сухарей, то моя страница2 будет отображаться ниже содержимого страницы1:

    <Router>
      <div>
        <Link to="/"><div className="routerStyle"><Glyphicon glyph="home" /></div></Link>
        <Route exact path="/" component={LandingPage}/>
        <Route path="/page1" component={Page1}/>
        <Route path="/page1/page2" component={Page2}/>
      </div>
    </Router>

Ответ:

Que. # 1: не нужно оборачивать <Breadcrumbs ..../> элемент внутри <Router> элемент внутри каждого компонента приложения. Это может быть потому, что включение <Router> элемент внутри каждого компонента приводит к "вложенности" Router элементы (обратите внимание, у нас есть Router тег на целевой странице); который не работает с react router v4,

Que. # 2: Обратитесь к ответу, официально помеченному здесь (ответ по palsrealm ниже)

3 ответа

Решение

Ваши хлебные крошки основаны на ссылках и работают так, как задумано. Чтобы отобразить страницы, вам нужно настроить Switch с Routeв нем, который будет загружать соответствующие компоненты при изменении пути. Что-то вроде

<Switch> 
    <Route path='/' component={Home}/>
    <Route path='/page1' component={Page1}/>
    <Route path='/page2' component={Page2}/>
</Switch>

Если вы хотите, чтобы крошка показать Home/Page1/Page2 ваш routes должно быть '/page1/page2' : 'Page 2', Route также должен измениться соответственно.

Редактировать: Ваш Router должно быть

 <Router>
      <div>
        <Link to="/"><div className="routerStyle"><Glyphicon glyph="home" /></div></Link>
        <Switch>
        <Route exact path="/" component={LandingPage}/>
        <Route exact path="/page1" component={Page1}/>
        <Route path="/page1/page2" component={Page2}/>
        </Switch>
      </div>
    </Router>

Это также может быть достигнуто с помощью HOC, который позволит вам вместо этого использовать объект конфигурации маршрута для установки хлебных крошек. Я здесь с открытым исходным кодом, но исходный код также ниже:

Breadcrumbs.jsx

import React from 'react';
import { NavLink } from 'react-router-dom';
import { withBreadcrumbs } from 'withBreadcrumbs';

const UserBreadcrumb = ({ match }) =>
  <span>{match.params.userId}</span>; // use match param userId to fetch/display user name

const routes = [
  { path: 'users', breadcrumb: 'Users' },
  { path: 'users/:userId', breadcrumb: UserBreadcrumb},
  { path: 'something-else', breadcrumb: ':)' },
];

const Breadcrumbs = ({ breadcrumbs }) => (
  <div>
    {breadcrumbs.map(({ breadcrumb, path, match }) => (
      <span key={path}>
        <NavLink to={match.url}>
          {breadcrumb}
        </NavLink>
        <span>/</span>
      </span>
    ))}
  </div>
);

export default withBreadcrumbs(routes)(Breadcrumbs);

withBreadcrumbs.js

import React from 'react';
import { matchPath, withRouter } from 'react-router';

const renderer = ({ breadcrumb, match }) => {
  if (typeof breadcrumb === 'function') { return breadcrumb({ match }); }
  return breadcrumb;
};

export const getBreadcrumbs = ({ routes, pathname }) => {
  const matches = [];

  pathname
    .replace(/\/$/, '')
    .split('/')
    .reduce((previous, current) => {
      const pathSection = `${previous}/${current}`;

      let breadcrumbMatch;

      routes.some(({ breadcrumb, path }) => {
        const match = matchPath(pathSection, { exact: true, path });

        if (match) {
          breadcrumbMatch = {
            breadcrumb: renderer({ breadcrumb, match }),
            path,
            match,
          };
          return true;
        }

        return false;
      });

      if (breadcrumbMatch) {
        matches.push(breadcrumbMatch);
      }

      return pathSection;
    });

  return matches;
};

export const withBreadcrumbs = routes => Component => withRouter(props => (
  <Component
    {...props}
    breadcrumbs={
      getBreadcrumbs({
        pathname: props.location.pathname,
        routes,
      })
    }
  />
));

Следующий компонент должен возвращать крошку на любой глубине, кроме как на домашней странице (по понятным причинам). Вам не понадобится React Router Breadcrumb. Мой первый публичный вклад, так что если я пропущу важную часть, было бы замечательно, если бы кто-то мог указать на это. я добавил &raquo; для расщепления крошки, но вы, очевидно, можете обновить это, чтобы соответствовать тому, что вам нужно.

import React from 'react'
import ReactDOM from 'react-dom'
import { Route, Link } from 'react-router-dom'
// styles
require('./styles/_breadcrumbs.scss')

// replace underscores with spaces in path names
const formatLeafName = leaf => leaf.replace('_', ' ')

// create a path based on the leaf position in the branch
const formatPath = (branch, index) => branch.slice(0, index + 1).join('/')

// output the individual breadcrumb links
const BreadCrumb = props => {
  const { leaf, index, branch } = props,
    leafPath = formatPath(branch, index),
    leafName = index == 0 ? 'home' : formatLeafName(leaf),
    leafItem =
      index + 1 < branch.length 
        ? <li className="breadcrumbs__crumb">
          <Link to={leafPath}>{leafName}</Link>
          <span className="separator">&raquo;</span>
        </li>
        : <li className="breadcrumbs__crumb">{leafName}</li>
  // the slug doesn't need a link or a separator, so we output just the leaf name

  return leafItem
}

const BreadCrumbList = props => {
  const path = props.match.url,
    listItems =
      // make sure we're not home (home return '/' on url)
      path.length > 1
      && path
        // create an array of leaf names
        .split('/')
        // send our new array to BreadCrumb for formating
        .map((leaf, index, branch) => 
          <BreadCrumb leaf={leaf} index={index} branch={branch} key={index} />
        )

  // listItem will exist anywhere but home
  return listItems && <ul className="breadcrumbs">{listItems}</ul>
}

const BreadCrumbs = props => 
  <Route path="/*" render={({ match }) => <BreadCrumbList match={match} />} />


export default BreadCrumbs
Другие вопросы по тегам