Portals
是reactjs16提供的官方解決方案,使得組件能夠脫離父組件層級掛載在DOM樹的任何位置。html
普通狀況下,組件的render函數返回的元素會被掛載在它的父級組件上。react
import DemoComponent from './DemoComponent'; render() { // DemoComponent元素會被掛載在id爲parent的div的元素上 return ( <div id="parent"> <DemoComponent /> </div> ); }
然而,有些元素須要被掛載在更高層級的位置。最典型的應用場景:當父組件具備overflow: hidden
或者z-index
的樣式設置時,組件有可能被其餘元素遮擋,這個時候你就能夠考慮要不要使用Portal使組件的掛載脫離父組件。例如:對話框,tooltip。git
import DemoComponent from './DemoComponent'; render() { // react會將DemoComponent組件直接掛載在真真實實的 dom 節點 domNode 上,生命週期還和16版本以前相同。 return ReactDOM.createPortal( <DemoComponent />, domNode, ); }
組件的掛載點雖然能夠脫離父組件,但組件的事件經過冒泡機制仍能夠傳給父組件。github
// 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);
codesegmentfault
React系列課程 入門
官網portalsapp