首页 > 专栏 > 前端 > 文章详情
ReactDOM 中和 render 并列的 unstable_renderSubtreeIntoContainer 实现Dialog弹窗实例 发布于:2021-03-31 16:15:48   来源:React   查看:5  讨论:0
这里我们引入Portal组件,这是一个经典的实现,最初的实现来源于React Bootstrap组件中的Overlay Mixin,后来应用越来越广泛。我们截取的关键代码如下:
import React from 'react';
import ReactDOM, {findDOMNode} from 'react-dom';
// import CSSPropertyOperations from './react/lib/CSSPropertyOperation'

export default class Portal extends React.Component{
  constructor (props) {
    super(props);
    //...
  };
  openPortal(props = this.props){
    this.setState({active: true});
    this.renderPortal(props);
    this.props.onOpen(this.node);
  };
  closePortal(isUnmounted = false){
    const resetPortalState = () => {
      if (this.node) {
        ReactDOM.unmountComponentAtNode(this.node);
        document.body.removeChild(this.node);
      }
      this.portal = null;
      this.node = null;
      if (isUnmounted !== true) {
        this.setState({active: false});
      }
    };
    if (this.state.active) {
      if (this.props.beforeClose) {
        this.props.beforeClose(this.node, resetPortalState);
      } else {
        resetPortalState();
      }
      this.props.onClose();
    }
  };
  renderPortal(props){
    if (!this.node) {
      this.node = document.createElement('div');
      //在节点增加到DOM之前,执行CSS防止无效的重绘
      this.applyClassNameAndStyle(props);
      document.body.appendChild(this.node);
    } else {
      //当新的props传下来的时候,更新CSS
      this.applyClassNameAndStyle(props);
    }
    let children = props.children;
    if (typeof props.children.type === 'function') {
      children = React.cloneElement(props.children, {closePortal: this.closePortal});
    }
    this.portal = ReactDOM.unstable_renderSubtreeIntoContainer(
        this,
        children,
        this.node,
        this.props.onUpdate
    )
  };
  render(){
    if (this.props.openByClickOn) {
      return React.cloneElement(this.props.openByClickOn, {onClick: this.handleWrapperClick})
    }
    return null;
  }
}
从Portal组价你可以看出,我们实现了一个“壳”,其中包括触发事件、渲染的位置以及关闭的方法,但它并不关心子组件的内容。当我们使用它的时候,可以这么写:
<Portal ref="myPortal">
  <Modal title="My modal">some content</Modal>
</Portal>

评论

  • 匿名