美文网首页
React:Ajax的使用

React:Ajax的使用

作者: SwiftBirds | 来源:发表于2019-07-20 12:53 被阅读0次

在弄清楚React中的Ajax的使用之前,首先需要理解如下的一些概念

异步&回调函数

异步

在JavaScript的世界中,所有代码都是单线程执行的。
由于这个“缺陷”,导致JavaScript的所有网络操作,浏览器事件,都必须是异步执行。异步执行可以用回调函数实现。

function a(){
    console.log('执行a');
    setTimeout(function(){
        console.log('a执行完毕')
    },1000)
};

function b(){
    console.log('执行b')
};

a();
b();

最终的运行结果为

执行a
执行b
a执行完毕

以上代码会先执行函数a,而且不会等到a中的延迟函数执行完才执行函数b, 在延迟函数被触发的过程中就执行了函数b,当js引擎的event 队列空闲时才会去执行队列里等待的setTimeout的回调函数,这就是一个异步的例子

即使时间设置为0,也是会照样先执行函数b

回调函数

在异步执行的模式下,每一个异步的任务都有其自己一个或着多个回调函数,这样当前在执行的异步任务执行完之后,不会马上执行事件队列中的下一项任务,而是执行它的回调函数,而下一项任务也不会等当前这个回调函数执行完,因为它也不能确定当前的回调合适执行完毕。例如:上述代码中的setTimeout就是一个回调函数。

在实际体验中,当我们访问购物网站时,浏览器请求加载图片资源是一个耗时操作,网络条件差时,会导致图片加载很慢。但是此时我们仍然可以点击购物按钮完成购物的操作。这是因为图片加载(Ajax)是一个异步请求。它并不会因为图片加载事件而阻塞其它JS事件

callback.PNG

Promise

Ajax是一个典型的异步操作

request.onreadystatechange = function () {
    if (request.readyState === 4) {
        if (request.status === 200) {
            return success(request.responseText);
        } else {
            return fail(request.status);
        }
    }
}

以上代码,Ajax根据网络请求的返回的状态码(请求成功还是失败)来决定执行回调函数success(request.responseText)或fail(request.status)。

这样不好看,而且不利于代码复用。而且要想做多重的异步操作,会导致经典的回调地狱

doSomething(function(result) {
  doSomethingElse(result, function(newResult) {
    doThirdThing(newResult, function(finalResult) {
      console.log('Got the final result: ' + finalResult);
    }, failureCallback);
  }, failureCallback);
}, failureCallback);

Promise的基本使用


doSomething()
.then(result => doSomethingElse(value))
.then(newResult => doThirdThing(newResult))
.then(finalResult => console.log(`Got the final result: ${finalResult}`))
.catch(failureCallback);

Promise最大的好处是在异步执行的流程中,把执行代码和处理结果的代码清晰地分离了

promise流程图.PNG

Promise对象doSomething()是异步的,当他在某个时间点执行成功后,会去回调then后面的doSomethingElse();doSomethingElse()也是异步的,当他执行成功后,会去回调doThirdThing();以此类推,形成了一个Promise链。
在回调地狱示例中,有 3 次 failureCallback 的调用,而在 Promise 链中只有尾部的一次调用。通常,一遇到异常抛出,promise 链就会停下来,直接调用链式中的 catch 处理程序来继续当前执行。

Promise的并行执行

除了串行执行若干异步任务外,Promise还可以并行执行异步任务。它依赖于前置的多个Promise对象,只有当这些Promise对象全部执行成功后,才会去执行then后面的回调函数。例如下面的promise对象p1和p2,这两个任务是可以并行执行的,用Promise.all()实现

var p1 = new Promise(function (resolve, reject) {
    setTimeout(resolve, 500, 'P1');
});
var p2 = new Promise(function (resolve, reject) {
    setTimeout(resolve, 600, 'P2');
});
// 同时执行p1和p2,并在它们都完成后执行then:
Promise.all([p1, p2]).then(function (results) {
    console.log(results); // 获得一个Array: ['P1', 'P2']
});

有些时候,多个异步任务是为了容错。多个Promise对象只需要执行成功一个即可。只需要获得先返回的结果即可。例如下面例子,由于p1执行较快,Promise的then()将获得结果'P1'。p2仍在继续执行,但执行结果将被丢弃这种情况下,用Promise.race()实现。

var p1 = new Promise(function (resolve, reject) {
    setTimeout(resolve, 500, 'P1');
});
var p2 = new Promise(function (resolve, reject) {
    setTimeout(resolve, 600, 'P2');
});
Promise.race([p1, p2]).then(function (result) {
    console.log(result); // 'P1'
});

接下来进入正题

React AJAX请求

常见的五种请求方案:

  • jQuery $.ajax
  • Fetch API
  • SuperAgent
  • Axios
  • Request

这五种方案我并未全部用过,具体用法请参见:

React ajax请求方案--英文版

React ajax请求方案--中文版

Axios初体验

官方文档

中文文档

axios基于promise用于浏览器和node.js的http客户端,具有如下特点:

  • 支持浏览器和node.js
  • 支持promise
  • 能拦截请求和响应
  • 能转换请求和响应数据
  • 能取消请求
  • 自动转换JSON数据
  • 浏览器端支持防止CSRF(跨站请求伪造)

axios是基于ajax的一次封装。在实际工程中,接口统一规范好后,各组件axios的请求部分基本一致,因此可以将该部分分离出来做二次封装。被调用时接受组件传入的url等参数。其中baseURL会自动加入到url参数之前

import axios from 'axios'
import {Modal} from 'antd'

export default class Axios {

    static ajax(options){
        return new Promise((resolve,reject) => {
            axios({
                url: options.url,
                baseURL:' https://www.easy-mock.com/mock/5d2bb8f85fb7810a6be03487/baseEndManager',
                method: 'get',
                timeout: 5000,
            }).then((response) => {
                if(response.status === 200){
                    let res = response.data;
                    resolve(res);
                }else{
                    Modal.info({
                        title: "警告",
                        content: "请求失败"
                    })
                    reject(response.data);
                }
            })
        })
    }
}

然后在不同的组件中调用axios时只需要传入URL等参数即可。接着将返回的response根据不同组件进行不同的解析。然后传入state中,从而达到渲染组件的目的。本例使用的mock数据,接口地址在此

import { Table,Card,Button } from 'antd';
import React from 'react'
// import userList from './../../config/userConfig'
import axios from './../../axios/index.js'


export default class User extends React.Component {
  constructor(props){
    super(props);
    this.state = {
      datasource: [],
    }
  }

  componentDidMount(){
    this.request();
  }

  request = () => {
    axios.ajax({
      url: '/users',
    }).then((res)=>{
      let userlist = res.result.list.map((item) => {
        item.key = item.id;
        return item;
      });
      this.setState({
        datasource: userlist,
      });
    })
  }

  render(){
    const columns = [
      {
        title: 'ID',
        dataIndex: 'id',
      },
      {
        title: '姓名',
        dataIndex: 'name',
      },
      {
        title: '年龄',
        dataIndex: 'age',
      },
      {
        title: '籍贯',
        dataIndex: 'city',
      },
      {
        title: '电子邮件',
        dataIndex: 'email',
      },
      {
        title: '入职时间',
        dataIndex: 'date',
      },
    ]
    return(
      <div>
        <Card>
          <Button type='danger' size="small">编辑</Button>
        </Card>
        <Card>
          <Table bordered columns={columns} dataSource={this.state.datasource}/>
        </Card>
      </div>  
    )
  }
}

Axios实际体验

在实践过程中,体会到Axios基于ajax和promise的特点,决定了axios是一个异步的过程。这个特点在使用echarts时会踩坑。

假设需要使用echarts制作条形图,数据需要通过axios从接口获取,由于echarts的条形图是在componentDidMount()中初始化和设置数据的。如果在componentDidMount()中通过调用axios来获取数据。由于axios是异步执行的,axios还未从接口取回来数据,echarts已经初始化完毕了,这时由于this.state.obj还未通过axios调用的接口数据赋值。此时echarts会渲染出一个无数据的条形图。即使在componentWillMount()中调用axios,仍然会导致该情况发生。

class Bar extends Component {
    constructor(props){
        super(props);
        this.state={
            obj: {
                week: [],
                data: [],
            }
        };
    }

    componentDidMount() {
        // 基于准备好的dom,初始化echarts实例
        var myChart = echarts.init(document.getElementById('bar'));
        // 绘制图表
        myChart.setOption({
            title: { text: '每周平均交易量' },
            tooltip: {},
            xAxis: {
                data: this.state.obj.week,
            },
            yAxis: {},
            series: [{
                name: '销量',
                type: 'bar',
                color: ['#dd6b66','#759aa0','#e69d87','#8dc1a9','#ea7e53','#eedd78','#73a373'],
                data: this.state.obj.data,
            }]
        });
    })
    
    render() {
        console.log(this.state.obj);
        return (
            <div id="bar" style={{ width: 800, height: 430 }}></div>
        );
    }
}

一种正确的做法是通过promise链,必须执行完axios的调用,才能执行echarts的数据初始化设置。核心代码如下,其余部分见上一个代码。

componentDidMount() {
        // 基于准备好的dom,初始化echarts实例
        var myChart = echarts.init(document.getElementById('bar'));
        // 绘制图表
        axios.ajax({
            url: '/charts',
        }).then((res) => {
            let weeks = res.result.list.map((item) =>{
                return item.week;
            });
            let datas = res.result.list.map((item) => {
                return item.data;
            })
            this.setState({
                obj: {
                    week: weeks,
                    data: datas,
                }
            });
        }).then(() => {
            myChart.setOption({
                title: { text: '每周平均交易量' },
                tooltip: {},
                xAxis: {
                    data: this.state.obj.week,
                },
                yAxis: {},
                series: [{
                    name: '销量',
                    type: 'bar',
                    color: ['#dd6b66','#759aa0','#e69d87','#8dc1a9','#ea7e53','#eedd78','#73a373'],
                    data: this.state.obj.data,
                }]
            });
        })
    }

相关文章

  • react-rxjs-ajax

    react使用rxjs的ajax请求方式

  • React:Ajax的使用

    在弄清楚React中的Ajax的使用之前,首先需要理解如下的一些概念 异步&回调函数 异步 在JavaScript...

  • (四)React请求接口数据

    React请求接口数据 一、React ajax React本身只关注于界面, 并不包含发送ajax请求的代码,前...

  • React 中使用 Ajax

    React是一个视图层框架,用于构建用户界面。在 MVC 架构中,它仅仅负责视图部分。在实际的开发过程中,往往需要...

  • React问题汇总

    React和AJax的使用 在页面中动态显示从后台获取到的数据,这个时候需要发送ajax请求.//在hook函数c...

  • React学习补充

    React 网络请求 方法一 原生请求,react自带的fetch请求方式: 方法二 ajax请求,react通过...

  • react最佳实践

    看到石墨的react文档。提到http://andrewhfarmer.com/react-ajax-best-p...

  • React中的“ajax”

    React没有ajax模块 集成其他的js库(如axios/fetch/jquery),发送ajax请求axios...

  • HTML5权威指南 | 第五部分 高级功能

    三十二、使用AJAX(上) Ajax起步: 使用Ajax事件: Ajax请求的错误处理: 中止Ajax请求: 三十...

  • 使用express的multer中间件结合前端ajax实现简单的

    使用ajax进行表单提交的时候,有多种方式可以选择,其中react提供的思路,将数据单独存放到state中进行操作...

网友评论

      本文标题:React:Ajax的使用

      本文链接:https://www.haomeiwen.com/subject/kkoylctx.html