背景
最近在和同事合作一个需求,其中很多模块都需要一个相同风格的简单弹窗组件,而项目中引入的antd-mobile无法直接满足需求,最后决定由我来做一次二次封装。
开始
一开始我的理解是封装一层样式,新增一些特有的属性,其他的props
透传就完事了,于是有了下面的组件
CommonModal
import React from 'react'
import Modal, { ModalProps } from 'antd-mobile'
interface IProps extends ModalProps {
content: string
commonModalClassName?: string
}
const CommonModal: React.FC<IProps> = (props) => {
const { commonModalClassName = '', content = '', ...resProps} = props
return (
<div className={`common-modal ${ commonModalClassName }`}>
<Modal {...resProps}>
<p className="common-modal-content">{ content }</p>
</Modal>
</div>
)
}
复制代码
看起来简单粗暴没毛病。
使用Hook优化
功能已经实现,但同事用的时候反馈,作为一个简单的弹窗,每次用的时候还需要定义好state
,还要引入CommonModal
组件, 比较麻烦
const [visible, setVisible] = useState(false)
const [content, setContent] = useState(false
...
复制代码
这时我想起来antd-mobile
的Modal
可以直接调用Modal.alert
来唤起弹窗,对于多处复用的弹窗,像这样封装一个可执行的方法是不错的。先看看antd-mobile
的实现。
export default function alert(){
const div: any = document.createElement('div');
document.body.appendChild(div);
function close() {
ReactDOM.unmountComponentAtNode(div);
if (div && div.parentNode) {
div.parentNode.removeChild(div);
}
}
ReactDOM.render(
<Modal
visible
transparent
title={title}
transitionName="am-zoom"
closable={false}
maskClosable={false}
footer={footer}
maskTransitionName="am-fade"
platform={platform}
wrapProps={{ onTouchStart: onWrapTouchStart }}
>
<div className={`${prefixCls}-alert-content`}>{message}</div>
</Modal>,
div,
);
}
复制代码
贴了部分核心代码,其实就是用ReactDOM来渲染弹窗,用dom.parentNode.removeChild来卸载弹窗。
用Hook实现
useCommonModal
import React from 'react'
import ReactDOM from 'react-dom'
import CommonModal, { CommonModalProps } from './CommonModal'
const CommonModal: React.FC<CommonModalProps> = ({...props}) => <CommonModal {...props} />
type IProps = Pick<CommonModalProps, 'title' | 'content' | 'btnText'>
const ModalClassName = 'hook-modal'
const useCommonModal = (props:IProps) => {
const close = useCallback(()=>{
let dom = document.getElementByClassName('hook-modal')[0]
ReactDOM.unmountComponentAtNode(dom)
if(dom && dom.parentNode){
dom.parentNode.removeChild(dom);
}
},[])
const show = useCallback(()=>{
const Root = document.body
let dom = document.getElementByClassName('hook-modal')[0]
if(!dom){
dom = document.createElement('div')
dom.className = ModalClassName
Root.appendChild(dom)
}
ReactDOM.render(
<CommonModal {...props}/>
, dom)
// 等价于
// const ele = React.createElement(CommonModal, { ...props}, null)
// ReactDOM.render(ele, dom)
},[])
return {
close,
show
}
}
复制代码
使用
const { show, close } = useCommonModal({
title: '',
content: '',
btnText: '',
})
复制代码
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END