/* 目的:这个组件是给menu中使用ModalTrigger的替代 原因:内出现的任何内容都会被认为是menu中的一部分, 从而在弹框内操作时menu也会响应键盘的事件,上下左右移动、回车等,弹框的container设置在body上也解决不了,具体原因要看antd源码 做法:生成一个新的div标签,ReactDom.render渲染到body上。 问题:1、context注入的内容读不到(建议用props);2、有组件未挂载更新state的warning(建议不要在外面强行卸载组件,让组件做完自己的生命周期); 后续:尝试了portal也解决不了问题,为了尽量小的影响范围才用的目前实现方式,想到更友好的实现再来修改, 当然也在调用的组件里维护state,写一个通用的Modal组件,每个需要的组件内用一下。 为什么没用MenuItemModelTrigger:看起来不同组件的menu.item有不同写法,不同style,就新写了一个。 */ import React, { useCallback, useState, useEffect } from 'react'; import useUnmount from 'react-use/lib/useUnmount'; import ReactDOM from 'react-dom'; import { Modal } from 'antd'; import { ModalProps } from 'antd/lib/modal'; export type ModalOverlayRender = (props: { close: () => void; }) => React.ReactNode; export type ModalChildrenRender = (props: { open: () => void; }) => React.ReactNode; /** * Modal触发器 */ export const ModalTriggerWithNewDom: React.FC<{ disabled?: boolean; overlay?: ModalOverlayRender; children?: ModalChildrenRender; } & Omit> = props => { const { disabled } = props; const [vis, setVis] = useState(false); const [container, setContainer] = useState(null as HTMLElement); const open = useCallback(() => { if (disabled) return; let div = document.createElement('div'); setContainer(div); setVis(true); }, [disabled]); const close = () => { setVis(false); }; const { children, overlay, afterClose, ...modalProps } = props; useEffect(() => { if (container) { ReactDOM.render( {overlay ? overlay({ close }) : <>} , container, ); } return () => { if (container) { ReactDOM.unmountComponentAtNode(container); } }; }, [vis, container]); useUnmount(() => { if (container) { ReactDOM.unmountComponentAtNode(container); } }); return <>{children && children({ open })}; }; export default ModalTriggerWithNewDom;