如何使用转换创建一个React Modal(附加到`<body>`)?

jiy*_*ong 49 javascript modal-dialog css-transitions reactjs

这个答案中有一个模态/sf/answers/1875236261/,它通过附加它来创建一个基于React的模态<body>.但是,我发现它与React提供的转换插件不兼容.

如何创建一个有过渡(在进入和离开期间)?

Gil*_*man 62

在2015年的反应中,Ryan Florence 展示了使用门户网站.这是你如何创建一个简单的Portal组件......

var Portal = React.createClass({
  render: () => null,
  portalElement: null,
  componentDidMount() {
    var p = this.props.portalId && document.getElementById(this.props.portalId);
    if (!p) {
      var p = document.createElement('div');
      p.id = this.props.portalId;
      document.body.appendChild(p);
    }
    this.portalElement = p;
    this.componentDidUpdate();
  },
  componentWillUnmount() {
    document.body.removeChild(this.portalElement);
  },
  componentDidUpdate() {
    React.render(<div {...this.props}>{this.props.children}</div>, this.portalElement);
  }
});
Run Code Online (Sandbox Code Playgroud)

然后你可以在React中做的一切你可以在门户网站内做...

    <Portal className="DialogGroup">
       <ReactCSSTransitionGroup transitionName="Dialog-anim">
         { activeDialog === 1 && 
            <div key="0" className="Dialog">
              This is an animated dialog
            </div> }
       </ReactCSSTransitionGroup>
    </Portal> 
Run Code Online (Sandbox Code Playgroud)

jsbin demo

你也可以看看Ryan的react-modal,虽然我还没有真正使用它,所以我不知道它对动画的效果如何.

  • 我想我们在`componentWillUnmount`中也需要一个`ReactDOM.unmountComponentAtNode(this.portalElement)`,不是吗?否则,React树仍然存在于内存中.它也在`react-modal`源https://github.com/reactjs/react-modal/blob/master/lib/components/Modal.js#L62. (3认同)

小智 30

我编写了应该帮助你的模块react-portal.

  • 什么了!伙计,这应该是#1答案. (2认同)

mpe*_*pen 23

反应15.x

这是本文中描述的方法的ES6版本:

import React from 'react';
import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';

export default class BodyEnd extends React.PureComponent {

    static propTypes = {
        children: PropTypes.node,
    };

    componentDidMount() {
        this._popup = document.createElement('div');
        document.body.appendChild(this._popup);
        this._render();
    }

    componentDidUpdate() {
        this._render();
    }

    componentWillUnmount() {
        ReactDOM.unmountComponentAtNode(this._popup);
        document.body.removeChild(this._popup);
    }

    _render() {
        ReactDOM.render(this.props.children, this._popup);
    }

    render() {
        return null;
    }
}
Run Code Online (Sandbox Code Playgroud)

只需将您想要的任何元素包装在DOM的末尾:

<BodyEnd><Tooltip pos={{x,y}}>{content}</Tooltip></BodyEnd>
Run Code Online (Sandbox Code Playgroud)

反应16.x

这是React 16的更新版本:

import React from 'react';
import ReactDOM from 'react-dom';

export default class BodyEnd extends React.Component {

    constructor(props) {
        super(props);
        this.el = document.createElement('div');
        this.el.style.display = 'contents'; // The <div> is a necessary container for our content, but it should not affect our layout. Only works in some browsers, but generally doesn't matter since this is at the end anyway. Feel free to delete this line.
    }

    componentDidMount() {
        document.body.appendChild(this.el);
    }

    componentWillUnmount() {
        document.body.removeChild(this.el);
    }

    render() {
        return ReactDOM.createPortal(
            this.props.children,
            this.el,
        );
    }
}
Run Code Online (Sandbox Code Playgroud)

工作实例


小智 9

正如其他答案所述,这可以使用门户网站完成.从v16.0 门户网站开始包含在React中.

<body>
  <div id="root"></div>
  <div id="portal"></div>
</body>
Run Code Online (Sandbox Code Playgroud)

通常,当您从组件的render方法返回一个元素时,它会作为最近父节点的子节点挂载到DOM中,但是通过门户,您可以将子节点插入DOM中的其他位置.

const PortalComponent = ({ children, onClose }) => {
  return createPortal(
    <div className="modal" style={modalStyle} onClick={onClose}>
      {children}
    </div>,
    // get outer DOM element
    document.getElementById("portal")
  );
};

class App extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      modalOpen: false
    };
  }

  render() {
    return (
      <div style={styles}>
        <Hello name="CodeSandbox" />
        <h2>Start editing to see some magic happen {"\u2728"}</h2>
        <button onClick={() => this.setState({ modalOpen: true })}>
          Open modal
        </button>
        {this.state.modalOpen && (
          <PortalComponent onClose={() => this.setState({ modalOpen: false })}>
            <h1>This is modal content</h1>
          </PortalComponent>
        )}
      </div>
    );
  }
}

render(<App />, document.getElementById("root"));
Run Code Online (Sandbox Code Playgroud)

这里查看工作示例.

  • 截至2018年1月的最新答案......一直到这里......让你想知道这个重复的问题是否应该考虑到 (2认同)