自我介绍
看官们好,我叫JetTsang,之前都是在掘金潜水来着,现在偶尔做一些内容输出吧。
引出
在React开发当中,使用到Modal模态框的时候,通常需要去维护1个state,同时在对应的回调函数当中更改这个state来控制显隐,
比如
import React, { useState } from 'react';
import { Button, Modal } from 'antd';
const App: React.FC = () => {
const [isModalOpen, setIsModalOpen] = useState(false);
const showModal = () => { setIsModalOpen(true); };
const handleOk = () => { setIsModalOpen(false); };
const handleCancel = () => { setIsModalOpen(false); };
return (
<>
<Button type="primary" onClick={showModal}>
Open Modal
</Button>
<Modal title="Basic Modal"
open={isModalOpen}
onOk={handleOk}
onCancel={handleCancel}
>
<p>Some contents...</p>
</Modal>
</>
);
};
export default App;
那么是否能实现不需维护这个状态来打开Modal
呢?
比如可以这样去用,用一个openModal
方法来实现打开modal
import React, { useState } from 'react';
import { Button, Modal } from 'antd';
const App: React.FC = () => {
const showModal = () => { setIsModalOpen(true); };
const handleOk = () => { setIsModalOpen(false); };
const handleCancel = () => { setIsModalOpen(false); };
return (
<>
<Button type="primary" onClick={()=>{
openModal(
<Modal title="Basic Modal"
onOk={handleOk}
onCancel={handleCancel}
>
<p>Some contents...</p>
</Modal>
)
}}>
Open Modal
</Button>
</>
);
};
export default App;
思路
可以利用render
方法,将模态框渲染到1个容器里,再利用DOM操作,把这个渲染好的容器添加到<body></body>
里
在React18当中
import ReactDOM from 'react-dom/client';
// 用一个fragment去做渲染容器
const container = document.createDocumentFragment();
// 将渲染容器转成 ReactDOMClient.Root 类型
const myModal = ReactDOMClient.createRoot(container)
// 调用rener方法,渲染
myModal.render(/* React.ReactElement */)
// 将渲染好的container,放入到body当中
document.body.appendChild(container);
18版本以前:
const container = document.createDocumentFragment();
// 对比18版本只是少了一个创建 ReactDOMClient.Root 的步骤
// 使用render方法,传入两个参数
ReactDOM.render(/* React.ReactElement类型 */, container);
实现
export default function OpenModal(Modal: React.ReactElement) {
const container = document.createDocumentFragment();
const myModal = ReactDOMClient.createRoot(container);
// 克隆的时候,顺便复写props
const cloneModal = React.cloneElement(Modal, {
// 设置为true
open: true,
// 重写取消方法
onCancel(e) {
// ⚠️这样强行卸载会很生硬,动画效果会没有,因此不采用
// myModal.unmount()
// ⚠️因此采用这种卸载方法
// 拿到关闭状态
const removeModal = React.cloneElement(cloneModal, {
open: false,
} as ModalProps);
// 重新渲染一下关闭状态的效果
myModal.render(removeModal);
Modal.props.onCancel?.(e);
}
})
myModal.render(cloneModal);
document.body.appendChild(container);
}
结尾
通过利用render
和cloneElement
,可以实现modal打开与关闭,而不用额外去维护open状态。当然除了React,类似的方案在Vue当中也是适用的。
写在最后
如果你需要简洁的确认框,官方也有App.useApp这种语法糖方法
模态框Modal、通知提醒框Notification、全局提示Message,这仨组件如果涉及到消费上下文
的,官方都是推荐hooks来调用。
© 版权声明
文章版权归作者所有,未经允许请勿转载,侵权请联系 admin@trc20.tw 删除。
THE END