如何優(yōu)雅的使用模態(tài)框
大家在使用antd中的模態(tài)框時(shí)是不是有一些痛點(diǎn),比如要處理visible顯示隱藏的邏輯伸头,
如果一個(gè)頁(yè)面中Modal太多酪术,我們就要去處理多個(gè)visible狀態(tài)阶剑,但是這樣一來(lái)頁(yè)面的邏輯就變的,
越來(lái)的越亂汤善,所以下面我就給大家介紹一下我是怎么一步一步去簡(jiǎn)化這個(gè)控件的使用過(guò)程的什猖。
Modal框的初體驗(yàn)
按照官網(wǎng)上的例子我寫(xiě)出了我的第一個(gè)模態(tài)框。
import { Modal, Button } from 'antd';
class App extends React.Component {
state = { visible: false }
showModal = () => {
this.setState({
visible: true,
});
}
handleOk = (e) => {
console.log(e);
this.setState({
visible: false,
});
}
handleCancel = (e) => {
console.log(e);
this.setState({
visible: false,
});
}
render() {
return (
<div>
<Button type="primary" onClick={this.showModal}>
Open Modal
</Button>
<Modal
title="Basic Modal"
visible={this.state.visible}
onOk={this.handleOk}
onCancel={this.handleCancel}
>
<p>Some contents...</p>
<p>Some contents...</p>
<p>Some contents...</p>
</Modal>
</div>
);
}
}
ReactDOM.render(<App />, mountNode);
后來(lái)我的頁(yè)面里又多了幾個(gè)Modal萎津,于是我又寫(xiě)了幾個(gè)Modal和幾個(gè)visible去控制顯示邏輯卸伞,在后來(lái)
我就崩潰了....。
狀態(tài)組件
后來(lái)我知道了什么是受控組件锉屈,什么是非受控組件荤傲。那么Modal框是要通過(guò)visible這個(gè)狀態(tài)去控制顯示隱藏,那么能不能通過(guò)封裝颈渊,將這個(gè)狀態(tài)讓它內(nèi)部消化類遂黍。后來(lái)我寫(xiě)了一個(gè)CommonModal,就是下面的例子俊嗽。
import React from "react";
import { Modal } from "antd";
export default class CommonModal extends React.Component {
state = { visible: false };
showModal = () => {
this.setState({
visible: true
});
};
handleOk = e => {
this.setState({
visible: false
});
this.props.onOk && this.props.onOk();
};
handleCancel = e => {
console.log(e);
this.setState({
visible: false
});
this.props.onCancel && this.props.onCancel();
};
render() {
return (
<div>
<button onClick={_ => this.showModal()}>打開(kāi)模態(tài)框</button> // 這個(gè)地方可以靈活配置
<Modal
{...this.props}
visible={this.state.visible}
onOk={this.handleOk}
onCancel={this.handleCancel}
>
{this.props.children}
</Modal>
</div>
);
}
}
上面的代碼我們只是簡(jiǎn)單的將antd的例子進(jìn)行了一個(gè)封裝雾家,可以將靈活配置的地方通過(guò)屬性傳遞過(guò)來(lái)這樣
外部就不需要進(jìn)行控制visible這個(gè)狀態(tài)了。好了绍豁,感覺(jué)用起來(lái)是不是舒服了一點(diǎn)芯咧,但是感覺(jué)還是有點(diǎn)不太舒服,比如我現(xiàn)在要在網(wǎng)絡(luò)出錯(cuò)是彈出一個(gè)Modal框竹揍,render里面寫(xiě)了好多renderXXModal啊敬飒,如果我在點(diǎn)擊某個(gè)按鈕,或者做某件事情的時(shí)候芬位,像調(diào)用一個(gè)方法一樣調(diào)出Modal框无拗,那該多好啊昧碉?其實(shí)antd給我們提供了這樣的組件英染,比如Modal.confirm, Modal.success 等等揽惹。于是找到我模仿antd寫(xiě)出了下面的代碼。
進(jìn)一步封裝
import { Modal } from 'antd';
import { ModalFuncProps } from 'antd/lib/modal';
import ReactDOM from 'react-dom';
import React from 'react';
/**
* example
*
* 1. 簡(jiǎn)單調(diào)用
* ShowModal();
* 2. onOk可以提供一個(gè)Promise
* ShowModal({
* content: <div>'Hello Modal'</div>,
* title: '我是測(cè)試的',
* onOk: () => Promise.resolve(123),
* onCancel: () => console.log('onCancel')
* })
* 3. onOk可以提供一個(gè)方法
* ShowModal({
* content: <div>'Hello Modal'</div>,
* title: '我是測(cè)試的',
* onOk: () => console.log('onOk'),
* onCancel: () => console.log('onCancel')
* })
* 4. onOk可以返回一個(gè)bool值來(lái)進(jìn)行判斷是否滿足條件四康,然后在進(jìn)行關(guān)閉
* 比如你有一個(gè)表格搪搏,想要進(jìn)行表格驗(yàn)證,如果不滿足驗(yàn)證就提示錯(cuò)誤箭养,而不是關(guān)閉
* 模態(tài)框
*
* 比如下面的列子
*
* state: any = {
* name: '',
* }
* renderForm = () => {
* const { name } = this.state;
* return (
* <Form.Item
* help={name.length === 0 ? '不能為空' : ''}
* validateStatus={name.length > 0 ? 'success' : 'error'}
* >
* <Input
* value={name}
* onChange={e => this.setState({name: e.target.value})}
* />
* </Form.Item>
* );
* }
*
* ShowModal({
* content: this.renderForm(),
* title: '我是測(cè)試的',
* onOk: () => {
* console.log('在這里做其他事情', this.state.name);
* return this.state.name.length > 0;
* },
* onCancel: () => console.log('onCancel')
* });
*
*/
function ShowModal(config?: ModalFuncProps) {
let currentConfig = { ...config, close, visible: true } as any;
const div = document.createElement('div');
document.body.appendChild(div);
function update(newConfig: ModalFuncProps) {
currentConfig = {
...currentConfig,
...newConfig,
};
render(currentConfig);
}
function destroy() {
const unmountResult = ReactDOM.unmountComponentAtNode(div);
if (unmountResult && div.parentNode) {
div.parentNode.removeChild(div);
}
}
function handleOnOk(props: ModalFuncProps) {
const { onOk } = props;
if (typeof onOk === 'function') {
const isVaild = props.onOk() || true;
if (isVaild) {
update({visible: false});
destroy();
}
} else if (typeof onOk === 'object') {
// tslint:disable-next-line:no-unused-expression
(onOk as any).finally = () => {
update({visible: false});
props.onOk();
destroy();
};
} else {
throw new Error('onOk只支持func或promise');
}
}
function handleOnCancel(props: ModalFuncProps) {
const { onCancel } = props;
update({visible: false});
if (typeof onCancel === 'function') {
props.onCancel();
destroy();
}
}
function render(props: ModalFuncProps) {
ReactDOM.render(
<Modal
{...props}
onOk={_ => handleOnOk(props)}
onCancel={_ => handleOnCancel(props)}
>
{ props.content ? props.content : <div>{'example'}</div>}
</Modal>,
div
);
}
render(currentConfig);
return {
update,
destroy,
};
}
export default ShowModal;
其實(shí)到這里我還是有些顧慮:
- 如果這樣去操作Dom是否會(huì)影響性能
- 如果服務(wù)器端渲染這樣document對(duì)象沒(méi)法使用了慕嚷,我說(shuō)的意思是比如您在服務(wù)器端發(fā)了一個(gè)網(wǎng)絡(luò)請(qǐng)求然后在失敗的時(shí)候調(diào)用了這個(gè)方法哥牍,這種情況毕泌。我也是猜測(cè),沒(méi)做實(shí)驗(yàn)嗅辣。
- 如果被高階函數(shù)包裹后撼泛,出現(xiàn)內(nèi)存泄漏了怎么辦。澡谭。愿题。