Bootstrap

React Native之Fetch简单封装、获取网络状态

1、Fetch的使用

  fetch的使用非常简单,只需传入请求的url

fetch('https://facebook.github.io/react-native/movies.json');

  当然是否请求成功与数据的处理,我们还需处理成功与失败的回调

function getMoviesFromApiAsync() {
  return fetch('https://facebook.github.io/react-native/movies.json')
    .then((response) => response.json())
    .then((responseJson) => {
      return responseJson.movies;
    })
    .catch((error) => {
      console.error(error);
    });
}

  通过response.json()将请求的返回数据转化成json数据以便使用。通过.then来对数据进行转化处理或最终暴露给调用者;.catch对异常的处理。

2、Fetch的简单封装

  废话少说,直接上代码;

  (1)封装工具

  代码如下:

//一个 Promise 就是一个代表了异步操作最终完成或者失败的对象
export default class HttpUtils{
    static get=(url)=>{
        return new  Promise(((resolve, reject) => {//resolve 和 reject 函数被调用时,分别将promise的状态改为fulfilled(完成)或rejected(失败)
            fetch(url)//默认是GET
                .then(response=>response.json())//把数据解析成json格式,然后取出
                .then(result=>{
                       resolve(result);//表示完成
                })
                .catch(error=>{
                        reject(error);//表示失败
                })
            })
        )
    };
    static post=(url,data)=>{
        return new Promise(((resolve, reject) => {
            fetch(url,{
                method:'POST',
                header:{
                    'Accept':'application/json',//告诉服务器,我们能接受json格式的返回类型,
                    'Content-Type':'application/json',//告诉服务器,我们提交的数据类型
                },
                body:JSON.stringify(data),//(把你想提交得数据序列化为json字符串类型,然后提交)body中的数据就是我们需要向服务器提交的数据,比如用户名,密码等
            })//返回 服务器处理的结果
                .then(response=>response.json())
                .then(result=>{
                    resolve(result);
                })
                .catch(error=> {
                    reject(error);
                })
            })
        )
    }
}
//数据转换成字符串 JSON.stringify(params)      //将数据JSON化 JSON.parse(responseJSON)
  (2)封装工具的使用

   1、首先引入头文件

import HttpUtils from './HttpUtils';

   2、实现对应的请求方法

  //get数据
onLoad=(url)=>{
    HttpUtils.get(url)//调用自定义组件方法,返回一个Promise
        .then(result=>{//then函数会返回一个新的promise
            this.setState({
                result:JSON.stringify(result),//序列化:转换为一个 (字符串)JSON字符串

            });
            console.log(result)
        })
        .catch(error=> {
            this.setState({
                result: JSON.stringify(error),//把错误信息格式化为字符串

            });
            console.log(result);
        })
};

//模拟登陆Post
onSubmit=(url,data)=>{
    HttpUtils.post(url,data)
        .then(result=>{
            this.setState({
                result:JSON.stringify(result),//序列化:转换为一个 (字符串)JSON字符串

            });
            console.log(result);
        })
        .catch(error=> {
            this.setState({
                result: JSON.stringify(error),//把错误信息格式化为字符串

            });
            console.log(result);
        })
};

   3、在需要使用的地方,发起请求;

        <TouchableOpacity style={{marginVertical: 20 }} onPress={() => this.onLoad('https://******/submit_ajax.ashx?action=APP_GetLines')}>
          <Text>发送Get网络请求</Text>
        </TouchableOpacity>
        <TouchableOpacity style={{marginVertical: 20 }} onPress={() => this.onSubmit('https://******/submit_ajax.ashx?action=APP_GetCardslist',{Uid:'37985'})}>
          <Text>发送POST网络请求</Text>
        </TouchableOpacity>

  更多内容,请参考:React Native网络请求传送门>>>

3、获取网络状态

/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 * @flow
 */

import React, { Component } from 'react';
import {
  AppRegistry,
  StyleSheet,
  Text,
  NetInfo,
  ToastAndroid,
  View
} from 'react-native';

class NetworkInfo extends Component {
  constructor(props) {
    super(props);

    this.state = {
      isConnected: null,
      connectionInfo: null,
    };

  }

  componentDidMount() {
    //网络是否连接的监听
    NetInfo.isConnected.addEventListener(
      'isConnected',
      this._handleConnectivityChange
    );

    //网络状态变化的监听
    NetInfo.addEventListener(
      'statusChange',
      this._handleNetStatusChange
    );


    //检测网络是否连接
    NetInfo.isConnected.fetch().done(
      (isConnected) => { this.setState({ isConnected: isConnected }); }
    );
    //检测网络连接状态
    NetInfo.fetch().done(
      (connectionInfo) => { this.setState({ connectionInfo }); }
    );
  }



  componentWillUnmount() {
    //卸载两个监听
    NetInfo.isConnected.removeEventListener(
      'isConnected',
      this._handleConnectivityChange
    );
    NetInfo.removeEventListener(
      'statusChange',
      this._handleNetStatusChange
    );
  }


  _handleConnectivityChange = (isConnected) => {
    ToastAndroid.show((isConnected ? 'online' : 'offline'), ToastAndroid.SHORT);
  }

  _handleNetStatusChange = (status) => {

    ToastAndroid.show('当然网络状态:' + status, ToastAndroid.SHORT);

  }

  render(){

   }
}

  这个组件已经在RN刚出来(俩平台同时支持)的时候就已经存在了,用法大家都已经很熟悉了,但是在0.48+版本中,出现了一些变化,前面的用法都会过期。

  主要完善了两个方面的问题

  - 目前的NetInfo API是分平台的.在iOS和Android平台上返回完全不同的值.

  - 目前的NetInfo API无法判定连接的手机网络是 2g, 3g, 还是 4g.
  贡献者为了不造成breaking changes,所以直接新增新的api,将前面的api改为黄色警告

  - `fetch`方法过时了,用`getConnection`替代
  - `change`事件过时了,用`connectionchange`替代.
  - `fetch`/`change`过时了,用`getConnection`/`connectionchange`替代。返回的枚举值也变了。具体查看下面的值 

ConnectionType(设备的网络类型):

  跨平台:

    - none - 设备处于离线状态。

            - wifi - 设备处于联网状态且通过wifi链接,或者是一个iOS的模拟器。

            - cellular - 设备是通过Edge、3G、WiMax或是LTE网络联网的。

            - unknown - 发生错误,网络状况不可知

     Android平台:

            - bluetooth - 蓝牙数据连接

            - ethernet - 以太网数据连接

            - wimax - WiMAX数据连接

  EffectiveConnectionType(无线网络类型) :

    - 2g 

    - 3g 

    - 4g 

    - unknown

  具体用法,请参考:NetInfo传送门>>>

4、@react-native-community/netinfo

  第一步:安装

yarn add @react-native-community/netinfo
或
npm install --save @react-native-community/netinfo

  第二步:关联项目

react-native link @react-native-community/netinfo

  第三步:在项目中引用

import NetInfo from "@react-native-community/netinfo";

  注意此处:使用过这个API之后,就不要再引用原有的NetInfo了,可能会引起冲突。如下:

import { NetInfo } from "react-native";

  案例代码。如下:

/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @format
 * @flow
 */

import React from 'react';
import {Text, View,TouchableWithoutFeedback} from 'react-native';
import NetInfo from '@react-native-community/netinfo';

export default class IsConnected extends React.Component<{}, $FlowFixMe> {
  state = {
    isConnected: null,
    // isConnectionExpensive: null,
  };
  // _checkIfExpensive = () => {
  //   NetInfo.isConnectionExpensive().then(isConnectionExpensive => {
  //     this.setState({isConnectionExpensive});
  //   });
  // };
  componentDidMount() {
    NetInfo.isConnected.addEventListener(
      'connectionChange',
      this._handleConnectivityChange,
    );
    NetInfo.isConnected.fetch().done(isConnected => {
      this.setState({isConnected});
    });
  }

  componentWillUnmount() {
    NetInfo.isConnected.removeEventListener(
      'connectionChange',
      this._handleConnectivityChange,
    );
  }

  _handleConnectivityChange = isConnected => {
    this.setState({
      isConnected,
    });
  };

  render() {
    return (
      <View style={{backgroundColor:'white',marginTop:20,flex:1}}>
        <Text>{this.state.isConnected ? 'Online' : 'Offline'}</Text>
      {/*  <TouchableWithoutFeedback onPress={this._checkIfExpensive}>
         <View>
           <Text>
             Click to see if connection is expensive:
             {this.state.isConnectionExpensive === true
               ? 'Expensive'
               : this.state.isConnectionExpensive === false
               ? 'Not expensive'
               : 'Unknown'}
           </Text>
         </View>
       </TouchableWithoutFeedback>*/}
      </View>
    );
  }
}

  提示:代码中注释部分,是进行判断是否是付费网络,仅支持Android,但是在iOS上也不会出错,但会有⚠️警告信息。

@react-native-community/netinfo传送门>>>

;