博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
使用 async/await 获取弹出框交互结果
阅读量:6418 次
发布时间:2019-06-23

本文共 6738 字,大约阅读时间需要 22 分钟。

利用async/await 关键字,我们可以优雅的处理异步逻辑。

比如调用网络接口可以直接await fetch(……)

事实上,在处理页面交互逻辑时使用async/await,也可以起到很好的解耦作用,写出更清晰的代码。

比如获取Modal弹框的交互结果:

后台系统在交互设计上经常使用模态弹框。很多UI框架都提供了方便易用的Modal组件,比如Ant design:

先来看一下antd官方的demo是怎么做的:

import { Modal, Button } from 'antd';class App extends React.Component {  state = { visible: false } // 还是需要维护一个visible state用来控制Modal的显示状态  showModal = () => {    this.setState({      visible: true,    });  }  handleOk = (e) => {    this.setState({      visible: false,    });  }  handleCancel = (e) => {    this.setState({      visible: false,    });  }  render() {    return (      

Some contents...

Some contents...

Some contents...

); }}ReactDOM.render(
, mountNode);复制代码

以上代码可以看出:受制于React通常的写法,在频繁使用Modal的场景下Antd的封装使用起来还是有些繁琐

  • 还是需要维护一个visible state,用来控制Modal是否显示
  • 如果外层组件只需要获取Modal内操作的结果,需要用props传递一个onChange方法进来,或者借助笨重的全局状态管理机制
  • 大量使用Modal时,会产生海量的重复代码
  • ……

当然,作为中后台系统的优秀解决方案,Antd的小伙伴帮我们封装了Modal.methods可以快速的创建一些简易的弹窗:

Modal.confirm({  title: 'Confirm',  content: 'Bla bla ...',  okText: '确认',  cancelText: '取消',});复制代码

这是一个不错的思路,但是Antd官方提供的methods功能非常有限。

我们来看一看能否在Antd Modal的基础上做一些改进:

希望能够实现result = await Modal.open()这样的调用方式。

一种思路是在实现一个Modal class,上面有static open这样一个方法,当调用open时,向页面插入一个modal,类似上面Modal.confirm的做法。

另一种办法,可以先在页面实例化一个modal,需要open的时候利用ref attribute获取到已经实例化的modal,并调用它的open 方法。 如下:

import React from 'react';import { Modal, Input } from 'antd';export default class AsyncModalDemo extends React.Component {  state = {    visible: false,    text: ''  }  open = () => {    this.setState({      visible: true,    });    return new Promise((resolve, reject) => {      this.resolve = resolve;      this.reject = reject;    });  }  close = () => {    this.setState({      visible: false,    });    if (this.reject && typeof this.reject === 'function') {      this.reject('cancel');    }  }  handleOk = () => {    if (typeof this.resolve === 'function') {      this.resolve(this.state.text);    }    delete this.reject;    this.close();  }  render() {    return 
hello
you can check result in devtool
{ const v = (e && e.target && e.target.value) || ''; this.setState({ text: v, }) }} value={this.state.text} >
}}复制代码

调用方式如下:

import React from 'react';import './App.css';import { Button } from 'antd';import AsyncModal from './components/async_modal';class App extends React.Component {  handleOpenModal = async () => {    if (this.refs.asyncModal) {      const result = await this.refs.asyncModal.open();      console.log(result)    }  }  render() {    return (      
); }}export default App;复制代码

这样,我们就可以使用await 获取到Modal内到交互结果了,并且做到了较好的解耦。

但是每次都要在Modal类里面写一堆open、close、handleOk这样的method,感觉很烦。那么有没有比较好的方式,实现代码复用呢?

首先尝试一下继承:

import React from 'react';import { Modal, Input } from 'antd';class AsyncModalBase extends React.Component {  state = {    visible: false,  }  open = () => {    this.setState({      visible: true,    });    return new Promise((resolve, reject) => {      this.resolve = resolve;      this.reject = reject;    });  }  close = () => {    this.setState({      visible: false,    });    if (this.reject && typeof this.reject === 'function') {      this.reject('cancel');    }  }}export default class AsyncModalDemo extends AsyncModalBase {  state = {    text: ''  }  handleOk = () => {    if (typeof this.resolve === 'function') {      this.resolve(this.state.text);    }    delete this.reject;    this.close();  }  render() {    return 
hello
you can check result in devtool
{ const v = (e && e.target && e.target.value) || ''; this.setState({ text: v, }) }} value={this.state.text} >
}}复制代码

open 和 close method 在 AsyncModalBase内实现,在AsyncModalDemo内只需要实现handleOk就可以了。这样就复用了open和close两个method。

然后尝试一下HOC:

import React from 'react';import { Modal, Input, Button } from 'antd';const ModalHoc = (modalProps = {}) => DefaultComponent => class extends React.Component {  state = {    visible: false,  }  open = () => {    this.setState({      visible: true,    });    return new Promise((resolve, reject) => {      this.resolve = resolve;      this.reject = reject;    });  }  close = () => {    this.setState({      visible: false,    });    if (this.reject && typeof this.reject === 'function') {      this.reject('cancel');    }  }  hanldeResolve = (...params) => {    if (typeof this.resolve === 'function') {      this.resolve(...params);    }    delete this.reject;    this.close();  }  render() {    return 
}}class Demo extends React.Component { state = { text: '', } handleOk = () => { this.props.hanldeResolve(this.state.text) } render() { return
hello
you can check result in devtool
{ const v = (e && e.target && e.target.value) || ''; this.setState({ text: v, }) }} value={this.state.text} >
}}export default ModalHoc()(Demo);复制代码

很容易封装出了一个ModalHOC,同时做到了比较好的代码复用和解耦。这样,我们只需要实现modal内的业务逻辑,如表单、选择器……。外层的调用方式还是保持一致。

对于使用Vue的同学,也可以封装一个AsyncModal。下面以element-ui/el-dialog为基础做一些改进:

modal_mixin:

export default {  data() {    return {      visible: false,    }  },  watch: {    visible(val) {      if (!val) {        if (typeof this.handleClear === 'function') {          this.handleClear();        }        if (this.reject) {          this.reject('放弃操作');        }      }    }  },  methods: {    open(...params) {      this.visible = true;      if (typeof this.handleInit === 'function') {        this.handleInit(...params);      }      return new Promise((resolve, reject) => {        this.resolve = resolve;        this.reject = reject;      });    },    handleResolve(...params) {      delete this.reject;      this.visible = false;      if (this.resolve) {        this.resolve(...params);      }    },    close() {      this.visible = false;    }  }}复制代码

async modal:

复制代码

调用:

复制代码

使用mixin做代码复用。看起来似乎比react版本更简单一些。

更多细节请见:

转载于:https://juejin.im/post/5cfdf301f265da1bc94ee247

你可能感兴趣的文章
AppServ开启虚拟主机
查看>>
如何定位和解决Andorid的内存溢出问题(大总结)
查看>>
Linux下php安装openSSL模块
查看>>
如何删除mysql数据库的日志文件
查看>>
Swift/OC计时器使用方法
查看>>
AD的备份与还原
查看>>
和第三代动词算子式代码生成器光配合的前后端分离示例代码
查看>>
502 Bad Gateway 错误的解决办法
查看>>
convirt(二)—— 创建第一台虚机
查看>>
足球——2011-2012意甲球队队标
查看>>
mysql性能优化
查看>>
网站出现安全证书过期的原因
查看>>
Vim编辑器的使用
查看>>
python实用小工具介绍
查看>>
CentOS 6.5 64 安装 mysql-5.7.19
查看>>
DNS基本原理
查看>>
iOS 中json解析数据出现中文乱码的问题
查看>>
spring工程在eclipse 运行报错:找不到ContextLoaderListener
查看>>
java连接AD域
查看>>
常见下载节点
查看>>