网络

很多移动应用都需要从远程地址中获取数据或资源。你可能需要给某个 REST API 发起 POST 请求以提交用户数据,又或者可能仅仅需要从某个服务器上获取一些静态内容——以下就是你会用到的东西。

使用 Fetch

React Native 提供了和 web 标准一致的 Fetch API,用于满足开发者访问网络的需求。如果你之前使用过XMLHttpRequest(即俗称的 ajax)或是其他的网络 API,那么 Fetch 用起来将会相当容易上手。这篇文档只会列出 Fetch 的基本用法,并不会讲述太多细节,你可以使用你喜欢的搜索引擎去搜索fetch api关键字以了解更多信息。

发起请求

要从任意地址获取内容的话,只需简单地将网址作为参数传递给 fetch 方法即可(fetch 这个词本身也就是获取的意思)

fetch('https://mywebsite.com/mydata.json');

Fetch 还有可选的第二个参数,可以用来定制 HTTP 请求一些参数。你可以指定 header 参数,或是指定使用 POST 方法,又或是提交数据等等:

fetch('https://mywebsite.com/endpoint/', {
  method: 'POST',
  headers: {
    Accept: 'application/json',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    firstParam: 'yourValue',
    secondParam: 'yourOtherValue',
  }),
})

提交数据的格式关键取决于 headers 中的Content-Type。Content-Type有很多种,对应 body 的格式也有区别。到底应该采用什么样的Content-Type取决于服务器端,所以请和服务器端的开发人员沟通确定清楚。常用的'Content-Type'除了上面的'application/json',还有传统的网页表单形式,示例如下:

fetch('https://mywebsite.com/endpoint/', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/x-www-form-urlencoded',
  },
  body: 'key1=value1&key2=value2',
})

可以参考Fetch 请求文档来查看所有可用的参数。

注意:使用 Chrome 调试目前无法观测到 React Native 中的网络请求,你可以使用第三方的react-native-debugger来进行观测。

处理服务器的响应数据

上面的例子演示了如何发起请求。很多情况下,你还需要处理服务器回复的数据。

网络请求天然是一种异步操作。Fetch 方法会返回一个Promise,这种模式可以简化异步风格的代码:

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);
    });
}

你也可以在 React Native 应用中使用 ES2017 标准中的async/await 语法:

// 注意这个方法前面有async关键字
async function getMoviesFromApi() {
  try {
    // 注意这里的await语句,其所在的函数必须有async关键字声明
    let response = await fetch(
      'https://facebook.github.io/react-native/movies.json',
    );
    let responseJson = await response.json();
    return responseJson.movies;
  } catch (error) {
    console.error(error);
  }
}

别忘了 catch 住fetch可能抛出的异常,否则出错时你可能看不到任何提示。

import React from 'react';
import { FlatList, ActivityIndicator, Text, View  } from 'react-native';

export default class FetchExample extends React.Component {

  constructor(props){
    super(props);
    this.state ={ isLoading: true}
  }

  componentDidMount(){
    return fetch('https://facebook.github.io/react-native/movies.json')
      .then((response) => response.json())
      .then((responseJson) => {
        this.setState({
          isLoading: false,
          dataSource: responseJson.movies,
        }, function(){

        });

      })
      .catch((error) =>{
        console.error(error);
      })
  }

  render(){
    if(this.state.isLoading){
      return(
        <View style={{flex: 1, padding: 20}}>
          <ActivityIndicator/>
        </View>
      )
    }

    return(
      <View style={{flex: 1, paddingTop:20}}>
        <FlatList
          data={this.state.dataSource}
          renderItem={({item}) => <Text>{item.title}, {item.releaseYear}</Text>}
          keyExtractor={(item, index) => item.id}
        />
      </View>
    )
  }
}

默认情况下,iOS 会阻止所有 http 的请求,以督促开发者使用 https。如果你仍然需要使用 http 协议,那么首先需要添加一个 App Transport Security 的例外,详细可参考这篇帖子

从 Android9 开始,也会默认阻止 http 请求,请参考相关配置

使用其他的网络库

React Native 中已经内置了XMLHttpRequest API(也就是俗称的 ajax)。一些基于 XMLHttpRequest 封装的第三方库也可以使用,例如frisbee或是axios等。但注意不能使用 jQuery,因为 jQuery 中还使用了很多浏览器中才有而 RN 中没有的东西(所以也不是所有 web 中的 ajax 库都可以直接使用)。

const request = new XMLHttpRequest();
request.onreadystatechange = (e) => {
  if (request.readyState !== 4) {
    return
  }

  if (request.status === 200) {
    console.log('success', request.responseText);
  } else {
    console.warn('error')
  }
};

request.open('GET', 'https://mywebsite.com/endpoint/')
request.send()

axios 用例:

import React, { Component } from 'react'
import { Text, View } from 'react-native'
import axios from 'axios'

export default class App extends Component {
  async componentDidMount() {
    let result = await axios({
      url: 'https://m.lagou.com/listmore.json?pageNo=2&pageSize=15'
    })

    console.log(result)
  }

  render() {
    return (
      <View>
        <Text> textInComponent </Text>
      </View>
    )
  }
}

需要注意的是,安全机制与网页环境有所不同:在应用中你可以访问任何网站,没有跨域的限制。

WebSocket 支持

React Native 还支持WebSocket,这种协议可以在单个 TCP 连接上提供全双工的通信信道。

const ws = new WebSocket('ws://localhost:8081');

ws.onopen = () => {
  // connection opened
  ws.send('something'); // send a message
}

ws.onmessage = (e) => {
  // a message was received
  console.log(e.data);
}

ws.onerror = (e) => {
  // an error occurred
  console.log(e.message);
}

ws.onclose = (e) => {
  // connection closed
  console.log(e.code, e.reason);
}

websocket 服务端:

const WebSocket = require('ws')
const ws = new WebSocket.Server({ port: 8081 })

let clients = {}
let clientName = 0

ws.on('connection', (client) => {
  client.name = ++clientName
  clients[client.name] = client

  client.on('message', (msg) => {
    broadcast(client, msg)
  })

  client.on('close', () => {
    delete clients[client.name]
    console.log(client.name + ' 离开了~')
  })
})

function broadcast(client, msg) {
  for (var key in clients) {
    clients[key].send(client.name + ' 说:' + msg)
  }
}

results matching ""

    No results matching ""