Сопоставление путей принципа реакции-маршрутизатора

внешний интерфейс JavaScript React.js регулярное выражение

Сначала взгляните на пример официального сайта react-router.

const BasicExample = () => (
  <Router>
      <Route exact path="/" component={Home} />
      <Route path="/about" component={About} />
      <Route path="/topics" component={Topics} />
    </div>
  </Router>
);

Эффект выполнения приведенного выше кодакликните сюда

Цель этой статьи — объяснить, как react-router отображает различные компоненты в соответствии с URL-адресом в браузере.Что касается изменения URL-адреса (компонент Link), обратитесь к следующей статье.Переход по ссылке по принципу реактивного маршрутизатора.

Основные зависимости path-to-regexp

react-router предоставляет специальный метод сопоставления маршрутов matchPath (расположенный в packages/react-router/modules/matchPath.js), который опирается на пакет path-to-regexp.

Входные данные path-to-regexp представляют собой строку пути (то есть значение пути, определенного в Route), а выходные данные состоят из двух частей.

  • регулярное выражение (ре)
  • Массив (ключи) (используется для записи ключевой информации параметра)

Для параметра в пути (в следующем примере: bar) path-to-regexp определит его как группу захвата при генерации регулярного и запишет имя параметра (bar) в массив ключей

var pathToRegexp = require('path-to-regexp')
var keys = []
var re = pathToRegexp('/foo/:bar', keys)
console.log(re);
console.log(keys);

// 输出
/^\/foo\/([^\/]+?)(?:\/)?$/i
[ { name: 'bar',
    prefix: '/',
    delimiter: '/',
    optional: false,
    repeat: false,
    partial: false,
    pattern: '[^\\/]+?' } ]

ядро matchPath

Метод matchPath сначала получает регулярное значение, соответствующее пути, определенному в Route, с помощью метода path-to-regexp, а затем выполняет регулярное сопоставление между сгенерированным регулярным выражением и путем в URL-адресе, чтобы определить, совпадает ли оно.

console.log(re.exec('/foo/randal'));   
console.log(re.exec('/foos/randal'));

// 输出
[ '/foo/randal', 'randal', index: 0, input: '/foo/randal' ]
null

Поскольку регулярное выражение, созданное с помощью path-to-regexp, создает группу захвата для части param и записывает ключ param в отдельный массив keys, ключ и значение param можно получить путем обхода результата регулярного сопоставления и ключей Массив Создайте ассоциацию следующим образом:

const match = re.exec('/foo/randal');
const [url, ...values] = match;

const params = keys.reduce((memo, key, index) => {
  memo[key.name] = values[index];
  return memo;
}, {})

console.log(params) // {"bar": "randal"}

Окончательный matchPath возвращает null для несопоставленных и объект для успешных совпадений.

return {
    path,    //  /foo/:bar
    url:     //  /foo/randal
    isExact, //  false
    params:  //  {"bar": "randal"}
  };

Отрисовка маршрута

Компонент Route поддерживает состояние (соответствие), а значение match исходит из результата выполнения matchPath, как показано ниже.

state = {
    match: this.computeMatch(this.props, this.context.router)
  };
  computeMatch({ computedMatch, location, path, strict, exact, sensitive }, router) {
  	 if (computedMatch) return computedMatch; // computedMatch留给Switch使用
    const { route } = router;
    const pathname = (location || route.location).pathname;

    return matchPath(pathname, { path, strict, exact, sensitive }, route.match);
  }

Маршрут создаст связанный компонент только в том случае, если state.match не равен нулю.

Компоненты, связанные с маршрутом, имеют различные формы (рендеринг, компонент, дочерние элементы). Разница между формой определения детей и рендером и компонентом в том, что выполнение детей не имеет ничего общего с соответствием.Даже если совпадение равно нулю, функция детей будет выполнена.Что касается того, почему существует такая конструкция, как дети, в следующей статье оКомпонент ссылкиупоминается в статье.

render() {
    const { match } = this.state;
    const { children, component, render } = this.props;
    const props = { match, ...};

    if (component) return match ? React.createElement(component, props) : null;

    if (render) return match ? render(props) : null;

    if (typeof children === "function") return children(props);

    return null;
  }

До сих пор было объяснено, как react-router отображает компоненты разных маршрутов в соответствии с URL-адресом, но иногда только использование маршрутов по-прежнему вызывает проблемы, такие как:

<Route path="/about" component={About}/>
<Route path="/:user" component={User}/>
<Route component={NoMatch}/>

Если в настоящее время используется URL-адрес /about, приведенная выше запись отобразит на странице компоненты About, User и NoMatch.На самом деле, мы хотим отобразить только компонент About.

Переключить префикс соответствия пути

В ответ на вышеуказанные проблемы вы можете обернуть его компонентом Switch.

<Switch>
  <Route path="/about" component={About}/>
  <Route path="/:user" component={User}/>
  <Route component={NoMatch}/>
</Switch>

После пакета Switch, если URL-адрес доступа — /about, будет отображаться только компонент About, а если URL-адрес — /abouts, будет отображаться только компонент User.

Особенностью компонента Switch является то, что для рендеринга из дочерних дочерних элементов выбирается только один маршрут.Для достижения цели рендеринга только одного коммутатор использует путь маршрута для соответствия фронту, вместо того, чтобы полагаться на метод рендеринга маршрута. для рендеринга компонента, но в коммутаторе.Начинается сопоставление пути маршрута, и как только совпадающий путь найден, он выбирается для рендеринга. Ключевой код Switch выглядит следующим образом

render() {
    const { route } = this.context.router;
    const { children } = this.props;
    const location = this.props.location || route.location;

    let match, child;
    // 子children相当于只是选项,Switch负责从中挑选与当前url匹配的Route,被选中的子Route才会触发render方法
    React.Children.forEach(children, element => {
      if (match == null && React.isValidElement(element)) {
        const {
          path: pathProp,
          exact,
          strict,
          sensitive,
          from
        } = element.props;
        const path = pathProp || from;

        child = element;
        match = matchPath(
          location.pathname,
          { path, exact, strict, sensitive },
          route.match
        );
      }
    });

    return match
      ? React.cloneElement(child, { location, computedMatch: match })
      : null;
  }

Вышеприведенный код передает результат выполнения matchPath в Route с помощью calculatedMatch в качестве ключа, что позволяет избежать повторного сопоставления, а метод ComputeMatch Route можно повторно использовать напрямую.

перейти к следующей статьеПереход по ссылке по принципу реактивного маршрутизатора