Portal 实现Modal组件

627 阅读1分钟

前言

Portal 提供了一种将子节点渲染到存在于父组件以外的 DOM 节点的优秀的方案。它解决了实现组件时候的一个痛点,比如当父组件有 overflow: hidden 或 z-index 样式时,但你需要子组件能够在视觉上“跳出”其容器。例如,对话框、悬浮卡以及提示框:

ReactDOM.createPortal(child, container)

1. SPA App 一般只有一个根结点,假如有一个api可以比较好的将一个组件mount在root以外,就不会受父级组件样式的影响

image.png

2.用createPortal实现一个Portal

  • class版
class Portal extends React.PureComponent{
    componentDidMount() { //首先去body下创建一个id=modal-root的标签
        this.rootEle = document.createElement('div');
        this.rootEle.setAttribute('id','modal-root');
        document.body.appendChild(this.rootEle);
        this.forceUpdate();
    }
    render(){ //这里只是简单的让modal组件显示和隐藏
        if(!this.rootEle) return null;
        return ReactDOM.createPortal(<div>
            {this.props.children}
        </div>, this.rootEle);
    }
}
- hook版

3.实现useModal

function useModal(){
    const [isShow, setIsShow] = useState(false);
    const show = useCallback(() => setIsShow(true), []);
    const hide = useCallback(() => setIsShow(false), []);
    const Modal = ({children}) => (isShow && <Portal>{children}</Portal>);
    return {
        show,
        hide,
        Modal,
    };
}

3.调用useModal

export default memo(function App(){
    const {show, hide, Modal} = useModal();
    return <>
        <button onClick={show}>modal显示</button>
        <Modal>
            <input type="text" />
            <button onClick={hide}>关闭</button>
        </Modal>
    </>
});

4.当点击 modal显示 button,请看浏览器里的element,是不是多了一个id="modal-root"的div

image.png 同时渲染结果如下:

image.png