注册
web

让弹窗更易于使用~

标题又名:简单弹窗、多弹窗、复杂弹窗怎么做代码和状态的解耦。


关键字:react / modal


问题


实际业务中,不乏弹窗组件中包含大量复杂的业务逻辑。如:


function Order() {
// 省略上百行方法状态
   const [visible,setVisible] = useState(false)
   const withModalState = useState<any>()
   
   return (
  <Modal>
      <Input/>
           <Input/>
<Select/>
<Checkbox/>
       </Modal>

  )
}

甚至还有多弹窗的情形。如:


function Order() {
// 省略上百行方法状态
   const [visible1,setVisible1] = useState(false)
   const [visible2,setVisible2] = useState(false)
   const [visible3,setVisible3] = useState(false)
   
   const withModalState1 = useState<any>()
   const withModalState2 = useState<any>()
   const withModalState3 = useState<any>()
   
   // 省略 不懂多少 handlexx
   return (
       <main>
        ...
           <Modal1></* 省略很多代码 */></Modal1>

           <Modal2></* 省略很多代码 */></Modal3>
           <Modal3></* 省略很多代码 */></Modal3>
       </main>
  )
}


非常的痛:



  1. 如果弹窗在处理完内部流程后,又还有返回值,这有又会有一大通的处理函数。
  2. 如果这些代码都写在一个文件中还是不太容易维护的。

而且随着业务的断增长,每次都这么写还是很烦的。


期望的使用方式


因此有没有一种更贴近业务实际的方案。


让弹窗只专注于自己的内部事务,同时又能将控制权交给调用方呢。


或者说我就是不喜欢 Modal 代码堆在一起……


如下:


// Modal1.tsx
export function Modal1(props) return <Modal></* ... */></Modal>

// 甚至可以将MOdal中的逻辑做的更聚合。通过2次封再导出给各方使用
export const function Check_XXX_Window() {/* */ return open(Modal1)}
export const function Check_XXX_By_Id_Window() { return open(Modal1)}
export const function Check_XXX_Of_Ohter_Window() { return open(Modal1)}

// Order.tsx
function Order() {

function xxHndanle {
const expect = Check_XXX_Window(Modal1,args) // 调用方法,传入参数,获得预期值 ,完成1个流程
}
return (
<main>
...
// 不实际挂载 Modal 组件
</main>

)
}

像这样分离两者的代码,这样处理起来肯定是清爽很多的。


实现思路


实现的思路都是一致的。



  1. 创建占位符组件,放到应用的某处。
  2. 将相关状态集管理,并与Modal做好关联。
  3. 暴露控制权。

因此基于不同的状态管理方案,实现是多种多样的。相信很多大佬都自己内部封装过不少了。


但是在此基础上,我还想要3点。



  1. API使用简单,但也允许一定配置。
  2. 返回值类型推导,除了帮我管理 close 和 open 还要让我用起来带提示的。
  3. 无入侵性,不依赖框架以外的东西。

ez-modal-react


emm......苦于市面上找不到这类产品(感觉同类并不多……讨论的也不多?)


于是我自己开源了一个。回应上文实现思路,可以点击看代码,几百行而已。



并不是突发奇想而来,其实相关特性早就在企业内部是使用多年了。我也是受前辈和社区启发。



基本特性



  1. 基于Promise封装
  2. 返回值类型推导
  3. 没有入侵性,体积小。

使用画面


import EasyModal, { InnerModalProps } from 'ez-modal-react';

+ interface IProps extends InnerModalProps<'fybe?'> /*传入返回值类型*/ {
+ age: number;
+ name: string;
+ }

export const InfoModal = EasyModal.create(
+ (props: Props) => {
return (
<Modal
title="Hello"
open={props.visible}
onOk={() => {
+ props.hide(); // warn 应有 1 个参数,但获得 0 个。 (property) hide: (result: "fybe?") => void ts(2554)
}}
onCancel={() => {
props.hide(null); //safe hide 接受 null 作为参数。它兼具 hide resolve 两种功能。
}}
>
<h1>{props.age}</h1>
</Modal>
);
});

+ // warn 类型 "{ name: string; }" 中缺少属性 "age",但类型 "ModalProps<Props, "fybe?">" 中需要该属性。
EasyModal.show(InfoModal, { name: 'foo' }).then((resolve) => {
console.log(resolve);
+ //输出 "fybe?"
});

也支持用 hook


import EasyModal, { useModal, InnerModalProps } from 'ez-modal-react';

interface IProps extends InnerModalProps<'苏振华'>/* 指定返回值类型 */ {
age: number;
name: string;
}

export const Info = EasyModal.create((props: Props) => {
const modal = useModal<Props>();

function handleOk(){
modal.hide(); // ts(2554) (property) hide: (result: "苏振华") => void ts(2554)
}

return <Modal open={modal.visible} onOk={handleOk} onCancel={modal.hide}></Modal>
});


EasyModal.show(Info,{age:18,}) // 缺少属性 "age"

还有一些特性如支持配置 hide 弹窗时的默认行为。(我认为大多数情况下可能用不上)



export const Info = EasyModal.create((props: Props) => {
const modal = useModal<Props>();

function handleOk(){
modal.hide();
+ modal.resolve('苏振华') // 需要手动抛出成功
+ modal.remove() // 需要手动注销组件。可用于反复打开弹窗,但是不希望状态被清除的场景。
}

return <Modal open={modal.visible} onOk={handleOk} onCancel={modal.hide}></Modal>

// Ohter.tsx
EasyModal.open(Info, {},
+ config:{
+ resolveOnHide:false, // 默认为 true
+ removeOnHide:false, // 默认为 true
+ }
);


当然以上是针对弹窗内有复杂业务场景的状况。


大部分场景都是调用方只在乎 open或close ,仅仅解耦代码这一项好处,就可以让代码变得清爽。


如常用的有展示类,设置类的弹窗,TS类型都用不上。


仓库


其他就不一一介绍了,主要的已经说完了,想了解更多,可以看看仓库。github


🎮 Codesandbox Demo


Codesandbox是一个线上集成环境,可以直接打开玩玩。点击 Demo Link 前往


初衷


让弹窗使用更轻松。



包名 ez 开头,是因为我DOTA在东南亚打多了,觉得该词特别贴切。



授之于鱼叉


GitHub仓库地址
ez-modal-react


觉得有用帮我点个星~~~ 感恩,有啥问题可以提出,看到会回复。如果有需要会持续维护该项目。


下列诸神,望您不吝赐教

作者:胖东蓝
来源:juejin.cn/post/7238917620849246263

0 个评论

要回复文章请先登录注册