前言
我们知道React是主张声明式的写法,不推荐命令式的写法。但是在一些特殊的场景中,使用命令式的写法会非常的高效。典型的就是Modal弹窗(衍生出Dialog,Confim等组件)。
假设我们使用声明式的写法
<Dialog
visible={this.state.visible}
title={intl('instance.action.release.title')}
style={{ width: '500px' }}
footer={this.getFooterButtons()}
onClose={this.onClose}
afterClose={this.afterClose}
>
<p>创建</p>
</Dialog>
我们再对比jquery中使用Dialog的方式
var d = dialog({
title: '欢迎',
content: '欢迎使用 artDialog 对话框组件!'
});
d.show();
很明显的感受到Modal的场景下,命令式的写法非常方便。
实现声明式Modal的几种方式
通过ReactDom 的Api创建新实例, 然后挂载到某个节点上(参考zent dialog
getInstance(props, element) {
ReactDom.render(
<Dialog
{...props}
/>,
element
);
}
const instance = getInstance({ visible: true }, document.getElmentById('J-dialog'));
通过react context + React router实现
定义一个context:
import React from 'react';
const initialState = {
title: null,
size: 'medium',
visible: false,
type: 'slide',
component: null,
toggleModal: () => {},
};
export default React.createContext(initialState);
分别定义 Provider:
import ModalContext from 'context/modal-context';
class ModalProvider extends Component {
static propTypes = {
children: PropTypes.node,
};
constructor(props) {
super(props);
this.toggleModal = this.toggleModal.bind(this);
this.state = {
title: null,
visible: false,
type: 'slide',
component: null,
toggleModal: this.toggleModal,
};
}
toggleModal(args) {
this.setState(args);
}
render() {
return <ModalContext.Provider value={this.state}>{this.props.children}</ModalContext.Provider>;
}
}
export default ModalProvider;
定义一个Modal的Consumer
const Modal = () => (
<ModalContext.Consumer>
{
({ type, visible, title, size, component }) => {
if (type === 'modal') {
return (
<Modal
autoClose={false}
hasMask
>
{component}
</Modal>
)
} else if (type === 'dialog') {
return (
<Dialog
title={title}
visible={visible}
footer={false}
>
{component}
</Dialog>
)
} else {
return null
}
}
}
</ModalContext.Consumer>
)
export default Modal
路由层面定义
<ModalProvider>
<Switch>
<Route path="/demo" component={Demo} />
</Switch>
<Modal />
</ModalProvider>
为了方便使用定义一个HOC函数
export default WrappedComponent => props => {
return (
<ModalContext.Consumer>
{context => <WrappedComponent toggleModal={context.toggleModal} {...props} />}
</ModalContext.Consumer>
);
};
真正使用
const handlerDialogClick = props => {
props.toggleModal({
title: 'Dialog弹窗',
visible: true,
type: 'dialog',
component: <div>Dialog</div>,
});
};
const Modal = props => (
<Button type="primary" onClick={() => handlerDialogClick(props)}>
Dialog弹窗测试
</Button>
);
const EnhancedModal = _.compose(withModal)(Modal);
export default EnhancedModal;