React 16 принес нам React Portals, однако они по-прежнему требуют от нас самостоятельной работы с элементами DOM. Сегодня мы представляем реакцию-канал, еще один способ рендеринга компонентов вне иерархии компонентов.

TL; DR

react-pipeit - это библиотека, которая экспортирует два основных компонента: <Inlet /> и <Outlet />. Дети, переданные на вход, будут отображаться во всех подключенных выходах.

Различные каналы управляются registry, совместно используемым через контекст a<ConduitProvider />. Вы также можете соединить два или более приложения React с помощью react-pipeline, создав единый реестр и поделившись им между всеми <ConduitProvider />.

Проблема

Несколько месяцев назад мне пришлось реализовать некоторые компоненты для отображения диалоговых окон подтверждения и модальных окон. Из-за того, как работают контексты стекирования CSS, я оказался в кроличьей норе.

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

Эта проблема была решена с помощью react-portal, который был частью стандартного React API с React 16. Однако API порталов требует, чтобы мы сами занимались управлением узлами DOM.

render() {
  return ReactDOM.createPortal(
    this.props.children,
    domNode,
  );
}

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

Представляем React-pipeline

React-pipeline - это библиотека, которая экспортирует два основных компонента: <Inlet /> и <Outlet />.

С порталами React вам нужно выбрать, в каком узле DOM вы хотите отобразить дочерние элементы. С помощью react-pipeline вы визуализируете дочерние элементы внутри Inlet, и эти дочерние элементы будут отображаться в подключенных Outlets, так что вы сможете избежать работы с DOM.

Чтобы подключить один или несколько входов к одному или нескольким выходам, вы должны пометить их с помощью стойки label. Кроме того, вы можете использовать стойки onConnect и onDisconnect, если вам нужно получать уведомления, когда вход или выход подключаются или отключаются.

Состояние подключенных трубопроводов и процесс подключения / отключения управляется registry. Реестр используется <ConduitProvider /> компонентом через контекст, поэтому и входы, и выходы могут подключаться при подключении или отключении.

Если вам нужно, вы даже можете подключить два или более приложения React, если вы используете один и тот же registry для каждого провайдера.

Практические варианты использования

Уровни приложений

Один из вариантов использования, где достаточно хорошо работает react-pipeline, - это создание разных уровней для приложения.

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

Вы можете создать столько слоев, сколько захотите, и разместить их в разных частях приложения, решив ранее упомянутую проблему стекирования CSS.

Отдельные компоненты

Еще одна замечательная вещь, которую вы можете сделать с помощью react-pipeit, - это отсоединить ваши компоненты, разбив их на разные части, чтобы отрисовать их отдельно.

Представьте, например, что у вас есть компонент для редактирования статей. В этом компоненте вы визуализируете заголовок, контент и панель инструментов, но при желании хотите разрешить пользователям вашего компонента отображать панель инструментов где-нибудь еще. В этом случае вы можете сделать что-то вроде этого:

Это здорово, потому что компонент Editor даже не привязан к реакции-каналу, он просто принимает контейнер. Это может быть даже компонент с отслеживанием состояния, и мы сможем отображать вещи в разных частях нашего приложения.

Рендеринг между приложениями

Возможно, вы разрабатываете приложение, отличное от React, которое использует React только для некоторых его частей. Если это так, и вам нужны разные реагирующие части, чтобы как-то общаться, вы можете сделать что-то вроде этого:

С большой властью приходит большая ответственность

Каналы - это мощное средство, но имейте в виду, что вы будете визуализировать элементы за пределами их естественного объема. Это может быть проблема с CSS. Если вы не будете осторожны, стили не будут каскадироваться так, как вы ожидаете.

Мы обнаружили, что реакция-проводник - один из полезных инструментов в нашем арсенале, но не всегда лучший инструмент для работы. Каналы увеличивают сложность вашего приложения. Если вы будете злоупотреблять им, вашему коду станет труднее следовать.