React Portal实现原生弹窗/对话框

914 阅读1分钟

React 实现弹窗/对话框有两种方案

  • 使用如Antd 等UI组件库:

    (Antd 对话框的Modal,也是基于 React Portals特性实现的)

  • 基于原生 React Portal

React Portal:

       React 16.3 新引入的API,提供了一种将子节点渲染到存在于父组件以外的DOM节点的技术方案,解决了如:Dialog、Tooltip等悬浮层的问题。

例:实现自定义弹窗

1. index.html 中,创建一个 dialog 对话框容器

<div id="root"></div>
<div id="dialog-root"></div>

2. 实现弹窗组件

components/PortalDialog/index.jsx

import { createPortal } from 'react-dom';
import { Button } from 'antd';
import './style.css';

const PortalDialog = (props) => {
  const { visible, children, onHide } = props;
  return visible
    ? createPortal(
        <div className="portal-custom">
          {children}
          <Button onClick={onHide}>close</Button>
        </div>,
        document.getElementById('dialog-root'),
      )
    : null;
};

export default PortalDialog;

components/PortalDialog/style.less

.portal-custom {
  position: absolute;
  padding: 20px;
  width: 500px;
  height: 300px;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  background-color: #fff;
  border-radius: 10px;
  border: 1px solid #ddd;
  box-shadow: 0px 0px 20px 2px #ddd;
}

3. Dialog弹窗组件的使用

import React, { useState } from 'react';
import { Button } from 'antd';
import PortalDialog from '@/components/PortalDialog';

const DialogPage = () => {
  const [isPortalVisible, setIsPortalVisible] = useState(false);

  const showPortal = () => {
    setIsPortalVisible(true);
  };

  const hidePortal = () => {
    setIsPortalVisible(false);
  };

  return (
    <>
      <Button style={{ marginLeft: '20px' }} onClick={showPortal}>
        Open Dialog(React Portals)
      </Button>
      <PortalDialog visible={isPortalVisible} onHide={hidePortal}>
        <div>dialog-children</div>
      </PortalDialog>
    </>
  );
};

export default DialogPage;