React 重溫之--Protals

什麼東西html

Portals 提供了一種很好的將子節點渲染到父組件之外的 DOM 節點的方式。
Plain Text
ReactDOM.createPortal(child, container)
第一個參數(child)是任何可渲染的 React 子元素,例如一個元素,字符串或碎片。第二個參數(container)則是一個 DOM 元素。node

簡單來講就是提供一種能夠自定義安排組件位置的API。通常狀況下組件都是被安插在距離最近的父節點上,經過這個API,能夠將組件安插在指定的DOM節點上。app

Plain Text
render() {
// React does not create a new div. It renders the children into domNode.
// domNode is any valid DOM node, regardless of its location in the DOM.
return ReactDOM.createPortal(less

this.props.children,
domNode,

);
}dom

典型用例是當父組件有 overflow: hidden 或 z-index 樣式,但你須要子組件可以在視覺上「跳出(break out)」其容器。例如,對話框、hovercards以及提示框:this

事件冒泡code

一個從 portal 內部會觸發的事件會一直冒泡至包含 React 樹 的祖先。component

Plain Text
<html>
<body>htm

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

</body>
</html>接口

Plain Text
// These two containers are siblings in the 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() {

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() {

// This will fire when the button in Child is clicked,
// updating Parent's state, even though button
// is not direct descendant in the DOM.
this.setState(prevState => ({
  clicks: prevState.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() {
// The click event on this button will bubble up to parent,
// because there is no 'onClick' attribute defined
return (

<div className="modal">
  <button>Click</button>
</div>

);
}

ReactDOM.render(<Parent />, appRoot);

在上面的例子中,app-root和modal-root是兩個平級的dom節點,從結構上來講,在modal-root上觸發的事件不會被app-root捕獲。

可是咱們使用createPortal接口將Modal組件的children綁定到modal-root節點上,而後再Parent組件中,包裹Modal組件並監聽onClick事件,並將Parent組件綁定到app-root節點上。

從真實的DOM結構上來看,mdal-root節點上的Modal組件中Child組件的onClick事件不該該被在app-root中Parent組件捕獲,但從虛擬DOM的解構上來看,Modal倒是Parent組件的子節點,這個事件冒泡仍是比較遵循虛擬DOM的。。

相關文章
相關標籤/搜索