a react tooltip component example based on React16 portals
Switch branches/tags
Nothing to show
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
public
src
.gitignore
README.md
package.json
yarn.lock

README.md

Blog

Merry Xmas

Before

Portals是React v16特别有价值的更新, 它的出现打破了父组件-子组件这种传统模式, 让你在任意DOM节点下操作组件变得简单.

Example

Antd的Modal: 当你打开DeveloperTools你会发现modal所在的节点并非是在#root下,而是和#root平级生成的新的Dom. 在v16之前你要做这件事并不容易, 起码你要这样写, 借助rc-util/lib/Portal来创建, 但是v16来了, 你只需要ReactDOM.createPortal(child, container)这样.

Journey

代码放到了这里.

这是一个最简单Modal, 点击button,会在button下展现一个Modal, 点击Modal上的Hidebutton会隐藏掉Modal.

点击后效果

可以明显的看到在和root平级地方多出了一个<div>, 这就是刚刚点击button通过portal创建的modal.

Core Code

// Modal.js

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

class Modal extends React.Component {
    constructor(props) {
        super(props);
        this.el = document.createElement('div');
    }
    componentDidMount() {
        document.body.appendChild(this.el);
    }
    componentWillUnmount() {
        document.body.removeChild(this.el);
    }
    render() {
        return ReactDOM.createPortal(this.props.children, this.el);
    }
}

export default Modal;
// App.js

class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      style: {},
      modalVisible: false,
    };
    this.showModal = this.showModal.bind(this);
  }
  showModal() {
    const dimensions = this.el.getBoundingClientRect();
    const left = dimensions.left;
    const top = dimensions.top + dimensions.height + 10;
    const height = 200;
    const width = 200;
    const style = { left, top, height, width };
    this.setState({
      style,
      modalVisible: true,
    });
  }
  render() {
    const modal = this.state.modalVisible && (
      <Modal>
        <div className="modal" style={this.state.style}>
          <p>Hello, World!</p>
          <button onClick={() => this.setState({ modalVisible: false })}>
            Hide
          </button>
        </div>
      </Modal>
    );
    return (
      <div className="App">
        { modal }
        <button
          ref={el => this.el = el}
          onClick={this.showModal}>
          Show
        </button>
      </div>
    );
  }
}
.modal {
  background-color: rgba(0,0,0,0.5);
  position: fixed;
  height: 100%;
  width: 100%;
  top: 0;
  left: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-direction: column;
}
  1. Modal是一个正常的rederable react component.
  2. 通过ReactDOM.createPortal(this.props.children, this.el);document.body下创建一个<div>,并将其子组件加进去.
  3. 生命周期结束(componentWillUnmount)将<div>移除.
  4. App.js中, 借助render方法,将Modal加进去, 可以放在<div className="App">下面任意位置,无影响(要保证不出错).
  5. 通过ref获得button的宽高及上下左右位置,设置modal的位置.

After

https://hackernoon.com/using-a-react-16-portal-to-do-something-cool-2a2d627b0202

这一篇文章, 大佬不光将modal建立在root之外, 更是建立在整个窗体之外.

可以在codepen中体验下.