Как использовать ReactDOM.createPortal() в React 16?

Я использую React 16 и нуждаюсь в порталах, но не могу найти никакой документации по этой функции. Кто-нибудь знает, как использовать это еще?

https://github.com/facebook/react/pull/10675

Спасибо за любой совет.

Ответ 1

React v16 только что выпустил пару часов назад (Yay!!), который официально поддерживает Portal.

Что такое портал? Так как долго он там был?

Порталы предоставляют первоклассный способ отображения дочерних элементов в DOM node, который существует вне иерархии DOM родительского компонента.

Portal не является новой концепцией в сообществе реагирования. Доступны многие библиотеки, поддерживающие такую ​​функциональность. например react-portal и react-gateway.

Что происходит при рендеринге любого реагирующего приложения?

Как правило, при рендеринге любого приложения React для создания всего дерева React используется один элемент DOM.

class HelloReact extends React.Component {
   render() {
       return (
          <h1>Hello React</h1>
       );
   }
}

ReactDOM.render(<HelloReact />, document.getElementById('root'));

Как вы можете видеть, мы превращаем наш реагирующий компонент в элемент DOM с идентификатором root.

Что такое портал и зачем он нужен? Почему он там?

Порталы - это способ рендерить детей React из основной иерархии DOM родительского компонента без потери контекста реакции. Я подчеркиваю это потому, что очень популярные библиотеки, такие как react-router, redux сильно использует контекст реакции. Таким образом, контекстная доступность при использовании Portal очень полезна.

В соответствии с react docs,

Типичный вариант использования порталов - это когда родительский компонент имеет переполнение: скрытый или z-индексный стиль, но вам нужно, чтобы ребенок визуально "разрывался" в своем контейнере. Например, диалоги, наводки и всплывающая подсказка.

Итак, с порталами вы можете визуализировать дерево с параллельным реагированием на другой DOM node, когда это необходимо. Несмотря на то, что он отображается в разных DOM node, родительский компонент может поймать неотображаемые события. Смотрите codepen, предоставленный в самих документах.

Ниже приведен пример:

// index.html
<html>
    <body>
        <div id="root"></div>
        <div id="another-root"></div>
    </body>
</html>

// index.jsx
const mainContainer = document.getElementById('root');
const portalContainer = document.getElementById('another-root');

class HelloFromPortal extends React.Component {
    render() {
         return (
           <h1>I am rendered through a Portal.</h1>
         );
    }
}

class HelloReact extends React.Component {
    render() {
        return (
             <div>
                 <h1>Hello World</h1>
                 { ReactDOM.createPortal(<HelloFromPortal />, portalContainer) }
             </div>
        );
    }
}

ReactDOM.render(<HelloReact />, mainContainer);

https://codesandbox.io/s/62rvxkonnw

Вы можете использовать элемент проверки devtools и видеть, что <h1>I am rendered through a Portal.</h1> отображается внутри тега #another-root, тогда как <h1>Hello World</h1> отображается внутри тега #root.

Надеюсь, что это поможет:)

Обновить: ответить комментарий @PhillipMunin.

В чем разница между ReactDOM.render и ReactDOM.createPortal?

  • Несмотря на то, что компонент, отображаемый через портал, отображается где-то в другом месте (вне текущего корня контейнера), он остается в виде дочернего элемента того же родительского компонента. (Кто вызвал ReactDOM.createPortal). Таким образом, любые события на дочернем сервере распространяются на родителя. (Ofc, это не работает, если вы вручную остановите распространение события.)

  • Тот же контекст доступен внутри компонента, отображаемого через портал. Но не в том случае, когда мы делаем ReactDOM.render напрямую.

Я создал еще одну демонстрацию, чтобы проиллюстрировать мою мысль. https://codesandbox.io/s/42x771ykwx

Ответ 2

Порталы создаются путем вызова метода createPortal внутри метода render вашего компонента.

render() {
  return (
    <div>
      {ReactDOM.createPortal(this.renderPortal(), this.props.portalEl)}
    </div>
  )
}

renderPortal должен возвращать содержимое, которое будет отображаться внутри портала, а portalEl - это внешний элемент DOM, который получит контент.

Кто-то недавно рассказал об этой информации на порталах в React tests.