在现代前端开发中,弹窗(Modal)是用户交互的重要组成部分。然而,随着业务复杂度的提升,我们常常遇到以下场景:
一个页面中多个弹窗,状态管理混乱
弹窗与触发按钮逻辑分散,维护困难
重复编写控制弹窗显示的布尔状态和开关函数
特别是在使用Ant Design(antd)这样的UI库时,我们通常需要为每个Modal维护一个visible状态和一个控制该状态的函数。这导致我们的组件代码充斥着大量的useState和条件渲染,使得代码冗长且难以维护。
有没有一种方法,可以让我们像调用函数一样简单地打开弹窗,而无需在组件中维护这些状态呢?
答案是肯定的。本文将介绍一种基于React Hooks的解决方案——createHooks。通过这个自定义钩子,我们可以将弹窗的调用方式从声明式转变为命令式,从而极大地简化代码结构。
什么是命令式弹窗?
命令式弹窗允许我们通过函数调用直接打开弹窗,无需预先在JSX中渲染Modal组件。这种方式有以下优势:
简化状态管理:不再需要为每个弹窗维护一个visible状态。
逻辑内聚:弹窗的触发逻辑和弹窗内容可以封装在一起。
代码简洁:减少模板代码,使组件更清晰。
createHooks的设计思路
createHooks是一个工厂函数,它接收一个Modal组件并返回一个命令式调用的函数。这个函数可以直接在事件处理函数中调用,并能够传递参数给Modal组件。同时,它还提供了更新和销毁弹窗的能力。
在本文中,我们将一步步实现createHooks,并探讨如何将其与antd Modal结合,打造一种优雅的弹窗使用方式。
让我们开始吧!
// 传统方式 ❌ 状态管理繁琐
const [visible, setVisible] = useState(false)
// 新方式 ✅ 一行代码搞定
showCreateModal({ title: '创建用户', data: userInfo })
废话不多说,直接上代码
import React, { createElement } from 'react';
import ReactDOM from 'react-dom';
interface ModalInstance {
destroy: () => void;
update: (props: any) => void;
}
const createHooks = <T extends Record<string, any> = {}>(
ModalComponent: React.ComponentType<any>
) => {
const showModal = (props?: T): ModalInstance => {
const container = document.createElement('div');
document.body.appendChild(container);
let currentProps = { ...props, open: true };
const destroy = () => {
ReactDOM.unmountComponentAtNode(container);
if (container.parentNode) {
container.parentNode.removeChild(container);
}
};
const update = (newProps: any) => {
currentProps = { ...currentProps, ...newProps };
render(currentProps);
};
const render = (props: any) => {
const element = createElement(ModalComponent, {
...props,
onCancel: (...args: any[]) => {
props.onCancel?.(...args);
destroy();
},
onOk: (...args: any[]) => {
props.onOk?.(...args);
destroy();
},
afterClose: destroy,
});
ReactDOM.render(element, container);
};
render(currentProps);
return {
destroy,
update,
};
};
return showModal;
};
export default createHooks;
使用方式
import React from 'react';
import { Button, Space } from 'antd';
import { showSimpleModal, showCreateModal } from '../components/modals';
const TestPage: React.FC = () => {
const handleSimple = () => {
console.log('打开简单弹窗');
showSimpleModal({
title: '测试弹窗',
onOk: () => console.log('确定'),
onCancel: () => console.log('取消'),
});
};
const handleCreate = () => {
console.log('打开创建弹窗');
showCreateModal({
onOk: (values: any) => {
console.log('创建数据:', values);
},
});
};
return (
<div style={{ padding: 20 }}>
<Space>
<Button type="primary" onClick={handleSimple}>
简单弹窗
</Button>
<Button onClick={handleCreate}>
创建弹窗
</Button>
</Space>
</div>
);
};
export default TestPage;










网友评论