AJAX API三驾马车: Axios vs . jQuery和Fetch

若是你曾经使用过相似 Angular 框架的经验,你会发现这些框架集成了开发一个应用应该具有的全部功能,例如用于进行HTTP调用的服务(Angular 中的 $HTTP )。javascript

React 是一个视图层框架,用于构建用户界面。在 MVC 架构中,它仅仅负责视图部分。在实际的开发过程当中,每每须要咱们引入一些第三方组件,好比今天要说的 AJAX APIcss

本文经过一个简单的示例,学习经过不一样的方式(如 AxiosXMLHttpRequestfetch API )使用来进行 AJAX 请求(GET、POST、PUT和DELETE),以获取、建立、更新和删除数据。java

AJAX

AJAX API

有不少的方案, 你所作的就是选择合适的解决方案:node

一、对JavaScriptPromise 比较熟悉,可使用 Axiosreact

二、喜欢使用前沿标准,可使用 fetch APIios

三、也可使用 jQuery ,但不建议仅仅为了进行API调用而引入整个库。git

能够直接使用 XMLHttpRequest 接口。github

Fetch API的示例

我推荐使用 create-react-app 来建立应用,由于它省去了好多的配置。ajax

npm install -g create-react-app
复制代码

经过执行如下命令建立并启动咱们的应用:react-ajax-demonpm

create-react-app react-ajax-demo
cd react-ajax-demo
npm start
复制代码

Fetch API

下面引自Mozilla MDN:

Fetch API 提供了一个获取资源的接口(包括跨域)。任何使用过 XMLHttpRequest 的人都能轻松上手,但新的API提供了更强大和灵活的功能集。

读取Reddit上发布的一些帖子,src/App.js

import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';

class App extends Component {

  constructor(props) {
    super(props);

    this.state = {
      posts: []
    };
  }  
  fetchFirst(url) {
    var that = this;
    if (url) {
      fetch('https://www.reddit.com/r/' + url + '.json').then(function (response) {
        return response.json();
      }).then(function (result) {
        that.setState({ posts: result.data.children, lastPostName: result.data.children[result.data.children.length - 1].data.name });
        console.log(that.state.posts);
      });
    }
  }  
  componentWillMount() {
      this.fetchFirst("reactjs");
  }    
  render() {

    return (
      <div className="App"> <header className="App-header"> <img src={logo} className="App-logo" alt="logo" /> <h1 className="App-title">React AJAX Example</h1> </header> <p className="App-intro"> <ul> {this.state.posts.map(post => <li key={post.id}>{post.title}</li> )} </ul> </p> </div> ); } } export default App; 复制代码

fetchFirst() 方法中,咱们发起了一个GET请求:

fetch('https://www.reddit.com/r/' + url + '.json').then(function (response) {
        return response.json();
}).then(function (result) {
    console.log(result.data.children);
});
复制代码

API很简单,须要的惟一参数就是资源的URI。这里它是一个JSON文件,也能够是任何类型的资源,如图像或其余类型。

**fetch(url)**在默认状况下发送GET HTTP请求。

还能够经过第二个参数中指定方法名来调用其余HTTP方法,如POST、PUT或DELETE。

例如,使用 fetch() 发送POST请求:

var form = new FormData(document.getElementById('login-form'));
fetch("/login", {
  method: "POST",
  body: form
});
复制代码

AJAX API调用时机

一个典型的 React 应用是一系列包含根组件、父组件以及子组件(以及子组件的子组件)的组件,这些组件能够可看做为一个树状结构。

这里会产生许多问题: 一、如何处理数据? 二、数据如何从组件流到其余组件? 三、最重要的是,在哪里放异步请求的代码?

componentWillMount() 是React生命周期的一个重要事件,执行时机在组件第一次渲染以前,在组件即将挂载时调用该事件。

前面的例子中,咱们就是在 componentWillMount() 事件内部发起 AJAX 请求。

其实还有几个地方能够这么作:

一、componentDidMount(): 这是官方推荐的地方

二、componentWillMount(): 官方不推荐

三、constructor():它被认为是反模式! 可是能够像 componentWillMount() 同样使用。

componentDidMount() vs componentWillMount()

componentWillMount() 方法在组件的第一次渲染以前被调用。任何人误觉得这是获取数据的最佳场所。但事实并不是如此!由于 fetch调用是异步的,这意味着在组件渲染以前异步请求有可能还没返回。通常采起的作法是:在 constructor() 设置初始状态,为了 React 能正确地渲染组件,在异步请求返回后触发组件的从新渲染。

componentDidMount() 方法是在组件第一次渲染以后调用的,所以能够放心在这里执行任何异步代码,这些操做能够是获取服务器数据,也能够是操做DOM。

在实现服务端渲染时,componentWillMount()会调用两次,所以会有两次请求发送给服务器,这是一种浪费。而componentDidMount()只会在客户端调用一次。

咱们对上面的示例作下改动:

componentDidMount() {
    this.fetchFirst("reactjs");
} 
复制代码

componentWillMount() vs constructor

从程序的角度分析,是否能够用 constructor 代替 componentWillMount()

表面上看确实是能够替代的,但这并非一种正确的方式。

由于咱们若是学过纯函数的话,都知道其实异步请求是一种典型的有反作用的非纯函数。若是组件构造函数中存非纯函数,React 会抛出一个警告, 而 componentWillMount() 中是容许非纯函数的。若是代码中须要更新其余组件中的状态,最好不要使用构造函数。

最后一个结论是:对于任何不产生反作用(如状态更新)的初始化代码使用构造函数,不然使用componentDidMount()。

组件之间通讯

另外一种方法是从父组件向子组件传递数据。固然,父组件也应该避免以前获取数据的方法,那么在哪里呢?父节点可使用React路由器钩子(如 onEnter() )获取数据,而后经过 props 将数据传递给子节点。

在本文示例中,因为只有一个组件,但这能够很容易地分解为如下内容:

Fetch.js

export default {
    fetchFirst: function(url){
        fetch('https://www.reddit.com/r/' + url + '.json').then(function (response) {
                return response.json();
        }).then(function (result) {
             return result.data.children;   
        }); 
    }  
}
复制代码

RedditPost.js

import React from "react";

class RedditPost extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      title: props.title,
      id: props.id
    }
  }

  componentWillReceiveProps(nextProps) {
    this.setState(nextProps);
  }

  render() {
            <li key={this.state.id}>{this.state.title}</li>
      );
    }
  }
}

RedditPost.propTypes = {
  id: React.PropTypes.number,
  title: React.PropTypes.string
};

RedditPost.defaultProps = {
  id: null,
  title: ""

};

export default RedditPost;
复制代码

App.js

import fetchFirst from "./Fetch";

import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';

class App extends Component {

  constructor(props) {
    super(props);

    this.state = {
      posts: []
    };
  }  

  componentDidMount() {

      fetchFirst("reactjs").then((posts)=>{
          this.state.posts = posts;
      });

  }    
  render() {

    return (
      <div className="App">
        <header className="App-header">
          <img src={logo} className="App-logo" alt="logo" />
          <h1 className="App-title">React AJAX Example</h1>
        </header>
        <p className="App-intro">
          <ul>
            {this.state.posts.map(post =>
              <RedditPost {...post}/>
            )}
          </ul>          
        </p>
      </div>
    );
  }
}

export default App;
复制代码

使用Redux State Manager

第三种方法是使用 Redux 这样的状态管理器。

从代码中的任何地方获取数据,而后将数据存储在全局存储中,全部其余组件均可以使用这些数据。

关于对 Redux 的学习,你能够自行了解,也能够读一下我以前写的几篇文章: 一、Redux-如何更优雅的修改全局状态 二、从新思考Redux

结尾

愈来愈多的企业在构建本身的网站时开始注重体验、性能,出现了大量的单页面应用,将 AJAX 这种无刷技术发挥到了极致。而咱们在使用 React 开发应用时能够有多种 AJAX 方案:

一、使用XMLHttpRequest,若是以为复杂,可直接使用 jQuery 。 二、Fetch API , 现代浏览器都支持,老版浏览器须要使用 polyfills 。 三、Axios :一个基于 promiseHTTP 库, 能够用在浏览器和 node.js 中。

相关文章
相关标签/搜索