これは
Reactのガイドを読んでいく記事です。
ガイドのリンク
ポータル
ポータルを介したイベントのバブリング
ポータルはDOMツリーのどこでも存在できる。
基本的にはReactの子要素と変わらずに振舞う。
イベントのバブリングも含まれ、ポータル内部で発火したイベントはReactツリーの親へ伝搬され、DOMツリー状の祖先ではなくてもその伝搬は行われる。
ドキュメントは以下のようなサンプルが書いてある。
// この 2 つのコンテナは 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.createElement('div'); } componentDidMount() { // ポータルの要素が DOM ツリーに挿入されるのは、 // Modal の子要素がマウントされた後になります。 // つまり、子要素は一旦どこにも結びつかない // DOM ノードへとマウントされるということです。 // もし子コンポーネントがマウント後すぐに DOM ツリーに結びついてほしい ―― // たとえば DOM ノードの大きさを測りたい、子孫要素で `autoFocus` を使いたいなど // ―― 場合は、 Modal に状態を持たせて 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);
ポータルから伝搬したイベントが親コンポーネントで補足できると言うことは、ポータルに本質的に依存することなく
柔軟な抽象化が可能であることを示す。
今日はここまで。