Какие порталы React решает? - PullRequest
0 голосов
/ 09 декабря 2018

Из документов реактивного портала:

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

Предлагаемое решение заключается в использовании:

// this line is rendered in `Portal1` component,
// which is rendered in `Parent1` component.
ReactDOM.createPortal(Child1, Container1)

Я не понимаю, что он решает.Почему помогает Child1 потомок Container1 вместо Parent1?

Возможно, мой вопрос неясен, так что если он этого не делает -> Чем это решение отличается от других решений для создания "диалогов, подсказок и подсказок"?

Ответы [ 3 ]

0 голосов
/ 09 декабря 2018

Когда вы инициализируете приложение React, ReactDOM запрашивает один контейнер DOM, для которого все ваши компоненты React будут отображаться в соответствии с этим DOM.Это делает React для всего процесса рендеринга.

Однако иногда вам необходимо контролировать некоторые компоненты React для рендеринга с использованием другого элемента DOM и взаимодействия с существующим приложением React.В этой ситуации удобно использовать порталы React.

Поскольку React создает виртуальные элементы в подполье, вы не можете преобразовать их в DOM элементы и вставить их непосредственно в DOM.React Portals позволяет вам передавать React Elements и указывать DOM контейнера для них.

Вот пример для демонстрации

У вас есть Modal компонент, который отображает divэлемент в центре.

function Modal() {
  return (
      <div style={{ position: 'absolute', left: '50%'}}>
          Message
      </div>
  );
}

Один компонент Modal помещается внутрь div, который имеет некоторую относительную позицию.

<div style={{ position: 'relative', left: 100 }}>
  <Modal />
</div>

Проблема заключается в том, что компонент Modal отображаетсяего положение относительно положения родительского div, но вам нужно показать его в центре окна.

Чтобы решить эту проблему, вы можете добавить свой компонент Modal непосредственно bodyэлемент.Это можно легко сделать с помощью порталов.

Вот решение для порталов.

function ModalRenderer() {
  return (
      React.createPortal(
         <Modal />,
         document.body
      )
  );
}

И использование компонента ModalRenderer в любом месте вашего приложения.

<div style={{ position: 'relative', left: 100 }}>
  <ModalRenderer />
</div>

Таким образом, ваш ModalRenderer решитэлемент контейнера для Modal, который не зависит от дерева вашего приложения.

0 голосов
/ 13 апреля 2019

Один хороший пример - разделить проблемы CSS.

Вот пример:

HTML

<div id="app-root"></div>
<div id="modal-root"></div>

CSS

.app {
  position: fixed;
  height: 100%;
  width: 100%;
  top: 0;
  left: 0;
  display: flex;
  justify-content: center;
  align-items: center;
  flex-direction: column;
}

.modal {
  background-color: rgba(0,0,0,0.5);
}

Babel

const appRoot = document.getElementById('app-root')
const modalRoot = document.getElementById('modal-root')

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      showModal: false
    }
    this.handleShow = this.handleShow.bind(this);
    this.handleHide = this.handleHide.bind(this);
  }

  handleShow() {
    this.setState({
      showModal: true
    })
  } 
  handleHide() {
    this.setState({
      showModal: false
    })
  } 
  render() {
    const modal = this.state.showModal ? (
      <Modal>
        <div className="modal">I am no longer centered!</div>
        </Modal>
    ) : null
    return (
      <div className='app'>
        Basic 
        <button onClick={this.handleShow}>
          Show Modal
        </button>
        {modal}
      </div>
    )
  }
}

class Modal extends React.Component {
  constructor(props) {
    super(props);
    this.el = document.createElement('div');
  } 

  componentDidMount(){
    modalRoot.appendChild(this.el)
  }
  componentWillUnmount() {
    modalRoot.removeChild(this.el)
  }
  render() {
    return ReactDOM.createPortal(
      this.props.children,
      this.el
    )
  }
}
ReactDOM.render(<App />, appRoot)

Замечания: 1. Основной текст имеет положение fixed и центрируется 2. Когда мы нажимаем кнопку, текст всплывает вверх.Обратите внимание, что текст больше не по центру!3. Если бы мы использовали его для чего-то вроде этого:

  <div className='app'>
    Basic 
    <button onClick={this.handleShow}>
      Show Modal
    </button>
    <div className="modal">I am centered ;(</div>
  </div>

Обратите внимание, что текст центрирован.Модал работает, перейдя на modal-root и прикрепив туда этот элемент DOM.Вы можете иметь свой собственный CSS под modal-root hood, отдельно от родительского компонента (app-root).

Теперь вы больше не обязаны прикреплять свои «дочерние» компоненты под родительские. В этом случае вы (app-root) прикрепляете его к своему брату (modal-root),Вы можете полностью прикрепить его к document.body или к любому элементу, который вы хотели.Другой привилегией, как и другим упомянутым пользователем, является всплывающее окно событий, как если бы этот дочерний компонент был их собственным дочерним элементом.

Родительский компонент в # app-root мог бы перехватить неперехваченное всплывающее событие из узла-брата # modal-root. Источник

0 голосов
/ 09 декабря 2018

В React V15 мы можем добавлять только дочерние доми в родительский дом. Это означает, что если вы хотите иметь элемент, вы должны создать новый div.Как это:

<div>
    {this.props.children}
</div>

ВРеагируйте на v16, не нужно создавать новый div. Мы можем использовать портал для добавления дочернего элемента в любой dom в dom-дереве.

ReactDOM.createPortal(
    this.props.children,
    domNode
  );

переполнение: скрытый или стиль z-index

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

Так что createPortal предлагает лучший вариант. Он может загружаться на верхний компонент родительского компонента. После монтирования элемента в другой домен он не будет защищен.


Событие и всплывающее окно

Даже компонент, установленный на другом компоненте, событие может подойти к компоненту-отцу.

...