React中基于状态复用Material UI Modal组件的优化方案问询
你的写法问题及优化方案
首先说下你当前写法的几个潜在问题:
- 若
open和deleteRole同时为true,会优先渲染open对应的内容,但业务里这两个操作通常不会同时触发,不过这种冲突场景还是要避免,防止出现意料外的显示问题。 onClose的写法有隐患:当两个状态都为false时,表达式会返回false,但ModalPopup的onClose需要接收一个函数,这时候会触发类型错误。- 所有条件判断堆在props里,代码可读性差,后续新增弹窗类型时会越来越难维护。
下面给你两种更优的实现方式:
方案一:用单个状态管理弹窗类型
把原来的两个布尔状态open和deleteRole替换成一个状态,用来标识当前打开的弹窗类型,从根源避免状态冲突:
import { useState } from 'react'; // 用单个状态管理当前弹窗类型,null表示无弹窗 const [currentModal, setCurrentModal] = useState(null); // 打开对应弹窗的方法 const openClientModal = () => setCurrentModal('client'); const openDeleteRoleModal = () => setCurrentModal('deleteRole'); // 通用关闭方法 const handleModalClose = () => setCurrentModal(null);
然后渲染单个ModalPopup:
<ModalPopup open={currentModal !== null} onClose={handleModalClose} title={currentModal === 'client' ? clientTitle : <DeleteConfirmDialog />} content={currentModal === 'client' ? clientContent : <DeleteRoleContent />} footer={ currentModal === 'client' ? clientAction : <DeleteRoleAction handleDeleteClose={handleModalClose} /> } maxWidth={currentModal === 'client' ? 'lg' : 'xs'} />
这种方式的优势:
- 彻底避免多弹窗状态同时激活的冲突
- 代码逻辑清晰,props中的条件判断直观易懂
- 后续新增弹窗类型,只需给
currentModal添加新的取值即可,扩展性强
方案二:抽离弹窗配置对象
如果后续需要新增更多弹窗类型,可以把每个弹窗的配置抽成独立对象,将配置与渲染逻辑分离,维护更方便:
// 定义所有弹窗的配置 const modalConfigs = { client: { title: clientTitle, content: clientContent, footer: clientAction, maxWidth: 'lg', onClose: () => setOpen(false) }, deleteRole: { title: <DeleteConfirmDialog />, content: <DeleteRoleContent />, footer: <DeleteRoleAction handleDeleteClose={() => setDeleteRole(false)} />, maxWidth: 'xs', onClose: () => setDeleteRole(false) } }; // 确定当前激活的弹窗配置 const activeConfig = open ? modalConfigs.client : deleteRole ? modalConfigs.deleteRole : null;
然后渲染弹窗:
{activeConfig && ( <ModalPopup open={true} onClose={activeConfig.onClose} title={activeConfig.title} content={activeConfig.content} footer={activeConfig.footer} maxWidth={activeConfig.maxWidth} /> )}
临时修复方案(保留原布尔状态)
如果你暂时不想修改状态结构,至少要修复onClose的类型问题,改成函数形式:
<ModalPopup open={open || deleteRole} onClose={() => { open && handleClose(); deleteRole && handleDeleteClose(); }} title={open ? clientTitle : <DeleteConfirmDialog />} content={open ? clientContent : <DeleteRoleContent />} footer={open ? clientAction : <DeleteRoleAction handleDeleteClose={handleDeleteClose}/>} maxWidth={open ? 'lg' : 'xs'} />
内容的提问来源于stack exchange,提问作者Nikhil
相关产品推荐
相关产品推荐

