TIL_65_React Portal


Portals
Portals
ポータルは、親コンポーネントDOM階層以外のDOMノードにサブオブジェクトをレンダリングするための最適な方法を提供します.
ReactDOM.createPortal(child, container)
最初のパラメータ(child)は、任意のタイプの要素、文字列、またはクリップをレンダリングできるReactサブアイテムです.
2番目のパラメータ(container)はDOM ELLIMENTである.
通常、構成部品レンダリング方法からエンティティを返すと、そのエンティティは親ノードに最も近い子ノードとしてDOMにマウントされます.
render() {
  // React는 새로운 div를 마운트하고 그 안에 자식을 렌더링
  return (
    <div>
      {this.props.children}
    </div>
  );
 }
DOMの他の場所にサブアイテムを挿入すると役に立つ場合があります.
render() {
  // React는 새로운 div를 생성하지 않고 `domNode` 안에 자식을 렌더링.
  // `domNode`는 DOM 노드라면 어떠한 것이든 유효하고,
  //그것은 DOM 내부의 어디에 있든지 상관없다.
  return ReactDOM.createPortal(
    this.props.children,
    domNode
  );
 }
ポータルサイトの典型的な例は、親コンポーネントにoverflow: hiddenまたはz-indexがあるが、視覚的に子供を「突き出す」必要がある場合もある.たとえば、ダイヤル、フーバーカード、ツールヒントなどです.
ポータルによるイベントの公開
portalがDOMツリー内の任意の場所に存在しても、他のすべての面で通常のreactサブアイテムのように表現されます.contextのような機能の動作は、サブアイテムがportalであるかどうかにかかわらず、完全に同じです.これは,DOMツリーにおけるポータルの位置にかかわらず,ポータルが「反応ツリー」に存在するためである.
入口内部で発生したイベントは、リアクションツリーに含まれる親に伝播します.ドムトリーでは上司でなくても
<html>
  <body>
    <div id="app-root></div>
    <div id="modal-root></div>
  </body>
</html>
#app-root内に位置するParent要素は、兄弟ノード#modal-root内の要素が伝播するイベントに捕捉されないときに捕捉することができる.
// 여기 이 두 컨테이너는 DOM에서 형제관계
const appRoot = document.getElementById('app-root');
const modalRoot = document.getElementById('modal-root');

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

componentDidMount() {
  // portal 엘리먼트는 Modal의 자식이 마운트된 후 DOM 트리에 삽입
  // 요컨대, 자식은 어디에도 연결되지 않은 DOM 노드로 마운트.
  // 만약 자식 컴퍼넌트가 마운트될 때 그것을 즉시 DOM 트리에 연결해야만 한다면,
  // 예를 들어, DOM 노드를 계산한다든지 자식 노드에서 'autoFocus'를 사용한다든지 하는 경우에,
  // Modal에 state를 추가하고 Modal이 DOM 트리에 삽입되어 있을 때만 자식을 렌더링 해라.
  modalRoot.appendChild(this.el);
}

componentWillUnmount() {
  modalRoot.removeChild(this.el);
}

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

class Parent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {clicks: 0};
    this.handleClick = this.handleClick.bind(this);
}

handleClick() {
  // 이것은 Child에 있는 버튼이 클릭 되었을 때 발생하고 Parent의 state를 갱신.
  // 비록 버튼이 DOM 상에서 직계 자식이 아니라고 하더라도.
  this.setState(state => ({
    clicks: state.clicks + 1
  }));
 }
render() {
  return (
    <div onClick={this.handleClick}>
      <p>Number of clicks: {this.state.clicks}</p>
      <p>
       Open up the browser DevTools
       to observe that the button
       is not a child of the div 
       with the onClick handler.
      </p>
      <Modal>
        <Child />
      </Modal>
     </div>
    );
   }
  }

function Child() {
  // 이 버튼에서의 클릭 이벤트는 부모로 버블링.
  // 왜냐, 'onClick' 속성이 정의되지 않았기 때문.
  return (
    <div className="modal">
      <button>Click</button>
    </div>
  );
}
ReactDOM.render(<Parent />, appRoot);
親コンポーネントからポータル内のbubblingイベントをキャプチャすることで、ポータルに依存せずに抽象開発をより柔軟に行うことができることを示します.たとえば、親は、ポータルが使用されているかどうかにかかわらず、エレメントをレンダリングするときに、のイベントをキャプチャできます.