ReactNative开发之网络请求

2017-07-04  本文已影响83人  寒桥

在ReactNative中,使用fetch实现网络请求。fetch同XMLHttpRequest非常类似,是一个封装程度更高的网络API,使用起来很简洁,因为使用了Promise。

Promise是异步编程的一种解决方案,比传统的解决方案--回调函数和事件--更合理、更强大。ES6将其写进了语言标准,统一了用法,原生提供了Promise对象。简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。

Promise对象代表一个异步操作,有三种状态:Pending(进行中)、Resolved(已完成)、Rejected(已失败)。Promise实例生成以后,可以分别指定“完成”和“失败”状态的回调函数。实现方式:链式调用方法,fetch中使用的就是该特性。

语法:
  fetch(参数)
  .then(完成的回调函数)
  .catch(失败的回调函数)

  fetch(url, opts)
  .then((response) => {
    // 网络请求成功执行的回调函数,得到响应对象,通过response可以获取请求的数据。例如:json、text等等
    return response.text();
    // return response.json();
  })
  .then((responseData) => {
    // 处理请求得到的数据
  })
  .catch((error) => {
    // 网络请求失败执行该回调函数,得到错误信息
  })

在POST请求中需要用到一个FormData的概念。

FormData

Web应用中频繁使用的一项功能就是表单数据的序列化,XMLHttpRequest2级定义了FormData类型,FormData主要用于实现序列化表单以及创建与表单格式相同的数据。

var data = new FormData();
data.append("name", "xiaoming");
append方法接收两个参数:键和值。分别对应表单字段的名字和字段中包含的值,添加多个键值对。

在jQuery中,“key1=value1&key2=value2”作为参数传入对象框架会自动封装成FormData形式。在Fetch中进行post请求时,需要自动创建FormData对象传给body。

示例1 - 网络请求的用法

import React, { Component } from 'react';
import {
  StyleSheet,
  Text,
  View,
  TouchableOpacity
} from 'react-native';

// GET请求
function getRequest(url) {
  var opts = {
    method: "GET"
  };

  fetch(url, opts)
  .then((response) => {
    return response.text(); // 返回一个带文本的对象
  })
  .then((responseText) => {
    alert(responseText);
  })
  .catch((error) => {
    alert(error);
  })
}

// POST请求
function postRequest(url) {
  // 将“key1=value1&key2=value2”封装成FormData形式
  let formData = new FormData();
  formData.append("username", "xiaoming");
  formData.append("password", "123");

  var opts = {
    method: "POST",
    body: formData
  };

  fetch(url, opts)
  .then((response) => {
    return response.text(); // 返回一个带文本的对象
  })
  .then((responseText) => {
    alert(responseText);
  })
  .catch((error) => {
    alert(error);
  })
}

var GetData = React.createClass({
  render: function () {
    return(
      <View style={styles.container}>
        <TouchableOpacity onPress={getRequest.bind(this, "http://demo.php?username=小&password=123")}>
          <View style={styles.btn}>
            <Text>GET</Text>
          </View>
        </TouchableOpacity>
        <TouchableOpacity opPress={postRequest.bind(this, "http://demo.php")}>
          <View style={styles.btn}>
            <Text>POST</Text>
          </View>
        </TouchableOpacity>
      </View>
    );
  }
});

var styles = StyleSheet.create({
  container: {
    flex: 1,
    marginTop: 30,
    backgroundColor: "cyan",
    flexDirection: "row",
    justifyContent: "space-around",
    alignItems: "center"
  },
  btn: {
    width: 60,
    height: 30,
    borderWidth: 1,
    borderRadius: 3,
    borderColor: "black",
    backgroundColor: "yellow",
    justifyContent: "center",
    alignItems: "center"
  },
});

module.exports = GetData;

运行结果:

运行结果.png

示例2 - 网络请求获取列表数据

import React, { Component } from 'react';
import {
  StyleSheet,
  Text,
  View,
  TouchableOpacity,
  ListView,
  Image
} from 'react-native';

/*
  展示电影列表

  逻辑:未获取数据时,显示等待页面;获取数据时,显示电影列表页面
  需要给state添加一个属性,用于记录数据获取状态
*/

var REQUEST_URL = "https://raw.githubusercontent.com/facebook/react-native/master/docs/MoviesExample.json";

var MovieList = React.createClass({
  // 设置初始状态值
  getInitialState: function () {
    // 定义一个dataSource对象
    var ds = new ListView.DataSource({
      rowHasChanged: (oldRow, newRow) => oldRow != newRow
    });
    return {
      // 数据是否下载成功的标识
      loaded: false,
      dataSource: ds
    };
  },
  // 请求数据
  getData: function () {
      fetch(REQUEST_URL)
      .then((response) => {
        return response.json();
      })
      .then((responseData) => {
        // 刷新组件,重新渲染组件,展示ListView
        // 得到新的数据,更新dataSource
        this.setState({
          loaded: true,
          dataSource: this.state.dataSource.cloneWithRows(responseData.movies)
        });
      })
      .catch((error) => {
        alert(error);
      })
  },

  render: function () {
    // 如果未请求到数据,提示“加载等待”页面
    if (!this.state.loaded) {
      return this.renderLoadingView();
    }

    // 电影列表
    return (
      <ListView
        style={styles.listView}
        dataSource={this.state.dataSource}
        initialListSize={10}
        renderHeader={this._renderHeader}
        renderRow={this._renderRow}
        renderSeparator={this._renderSeparator}
      />
    );
  },
  // 组件挂载完成 生命周期函数
  componentDidMount: function () {
    // 组件挂载后,开始请求数据
    this.getData();
  },

  // 等待加载页面
  renderLoadingView: function () {
    return(
      <View style={styles.loadingContainer}>
        <Text style={styles.loadingText}>Loading movies ...</Text>
      </View>
    );
  },

 // 渲染行
 _renderRow: function (movie) {
   return (
     <View style={styles.rowContainer}>
       <Image style={styles.thumbnail} source={{uri:movie.posters.thumbnail}}/>
       <View style={styles.textContainer}>
         <Text style={styles.title}>{movie.title}</Text>
         <Text style={styles.year}>{movie.year}</Text>
       </View>
     </View>
   );
 },

 // 渲染头部
 _renderHeader: function () {
   return (
     <View style={styles.header}>
       <Text style={styles.header_text}>Movie List</Text>
       <View style={styles.headerSeparator}></View>
     </View>
   );
 },

 // 渲染分割线
 _renderSeparator: function (sectionID: number, rowID: number) {
   var style = {
     height: 1,
     backgroundColor: "#CCC"
   };

   return (
     <View style={style} key={sectionID + rowID}></View>
   );
 }
});

var styles = StyleSheet.create({
  // Loading样式
  loadingContainer: {
    flex: 1,
    marginTop: 25,
    backgroundColor: "cyan",
    justifyContent: "center",
    alignItems: "center",
  },
  loadingText: {
    fontSize: 30,
    fontWeight: "bold",
    textAlign: "center",
    marginLeft: 10,
    marginRight: 10
  },
  // ListView Row样式
  rowContainer: {
    flexDirection: "row",
    padding: 5,
    alignItems: "center",
    backgroundColor: "#F5FCFF"
  },
  thumbnail: {
    width: 53,
    height: 81,
    backgroundColor: "gray"
  },
  textContainer: {
    flex: 1,
    marginLeft: 10
  },
  title: {
    marginTop: 3,
    fontSize: 18,
    textAlign: "center"
  },
  year: {
    marginTop: 3,
    marginBottom: 3,
    textAlign: "center"
  },
  // List Header样式
  header: {
    height: 44,
    backgroundColor: "#F5FCFF"
  },
  header_text: {
    flex: 1,
    fontSize: 20,
    fontWeight: "bold",
    textAlign: "center"
  },
  headerSeparator: {
    height: 1,
    backgroundColor: "#CCC"
  },
  listView: {
    marginTop: 25,
    backgroundColor: "#F5FCFF"
  }
});

module.exports = MovieList;

运行结果

运行结果.png
上一篇下一篇

猜你喜欢

热点阅读