react portals

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

官方DEMO

// 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系列課程 入門

refs

官網portalsapp

相關文章
相關標籤/搜索