在ReactNative中,使用fetch實(shí)現(xiàn)網(wǎng)絡(luò)請(qǐng)求。fetch同XMLHttpRequest非常類似芙粱,是一個(gè)封裝程度更高的網(wǎng)絡(luò)API,使用起來很簡(jiǎn)潔氧映,因?yàn)槭褂昧薖romise春畔。
Promise是異步編程的一種解決方案,比傳統(tǒng)的解決方案--回調(diào)函數(shù)和事件--更合理岛都、更強(qiáng)大律姨。ES6將其寫進(jìn)了語(yǔ)言標(biāo)準(zhǔn),統(tǒng)一了用法臼疫,原生提供了Promise對(duì)象择份。簡(jiǎn)單說就是一個(gè)容器,里面保存著某個(gè)未來才會(huì)結(jié)束的事件(通常是一個(gè)異步操作)的結(jié)果多矮。
Promise對(duì)象代表一個(gè)異步操作缓淹,有三種狀態(tài):Pending(進(jìn)行中)、Resolved(已完成)塔逃、Rejected(已失斚曜尽)荠雕。Promise實(shí)例生成以后,可以分別指定“完成”和“失敗”狀態(tài)的回調(diào)函數(shù)。實(shí)現(xiàn)方式:鏈?zhǔn)秸{(diào)用方法揭保,fetch中使用的就是該特性。
語(yǔ)法:
fetch(參數(shù))
.then(完成的回調(diào)函數(shù))
.catch(失敗的回調(diào)函數(shù))
fetch(url, opts)
.then((response) => {
// 網(wǎng)絡(luò)請(qǐng)求成功執(zhí)行的回調(diào)函數(shù)舍哄,得到響應(yīng)對(duì)象钓猬,通過response可以獲取請(qǐng)求的數(shù)據(jù)。例如:json帐萎、text等等
return response.text();
// return response.json();
})
.then((responseData) => {
// 處理請(qǐng)求得到的數(shù)據(jù)
})
.catch((error) => {
// 網(wǎng)絡(luò)請(qǐng)求失敗執(zhí)行該回調(diào)函數(shù)比伏,得到錯(cuò)誤信息
})
在POST請(qǐng)求中需要用到一個(gè)FormData的概念。
FormData
Web應(yīng)用中頻繁使用的一項(xiàng)功能就是表單數(shù)據(jù)的序列化疆导,XMLHttpRequest2級(jí)定義了FormData類型赁项,F(xiàn)ormData主要用于實(shí)現(xiàn)序列化表單以及創(chuàng)建與表單格式相同的數(shù)據(jù)。
var data = new FormData();
data.append("name", "xiaoming");
append方法接收兩個(gè)參數(shù):鍵和值澈段。分別對(duì)應(yīng)表單字段的名字和字段中包含的值悠菜,添加多個(gè)鍵值對(duì)。
在jQuery中败富,“key1=value1&key2=value2”作為參數(shù)傳入對(duì)象框架會(huì)自動(dòng)封裝成FormData形式悔醋。在Fetch中進(jìn)行post請(qǐng)求時(shí),需要自動(dòng)創(chuàng)建FormData對(duì)象傳給body兽叮。
示例1 - 網(wǎng)絡(luò)請(qǐng)求的用法
import React, { Component } from 'react';
import {
StyleSheet,
Text,
View,
TouchableOpacity
} from 'react-native';
// GET請(qǐng)求
function getRequest(url) {
var opts = {
method: "GET"
};
fetch(url, opts)
.then((response) => {
return response.text(); // 返回一個(gè)帶文本的對(duì)象
})
.then((responseText) => {
alert(responseText);
})
.catch((error) => {
alert(error);
})
}
// POST請(qǐng)求
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(); // 返回一個(gè)帶文本的對(duì)象
})
.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;
運(yùn)行結(jié)果:
示例2 - 網(wǎng)絡(luò)請(qǐng)求獲取列表數(shù)據(jù)
import React, { Component } from 'react';
import {
StyleSheet,
Text,
View,
TouchableOpacity,
ListView,
Image
} from 'react-native';
/*
展示電影列表
邏輯:未獲取數(shù)據(jù)時(shí)芬骄,顯示等待頁(yè)面猾愿;獲取數(shù)據(jù)時(shí),顯示電影列表頁(yè)面
需要給state添加一個(gè)屬性德玫,用于記錄數(shù)據(jù)獲取狀態(tài)
*/
var REQUEST_URL = "https://raw.githubusercontent.com/facebook/react-native/master/docs/MoviesExample.json";
var MovieList = React.createClass({
// 設(shè)置初始狀態(tài)值
getInitialState: function () {
// 定義一個(gè)dataSource對(duì)象
var ds = new ListView.DataSource({
rowHasChanged: (oldRow, newRow) => oldRow != newRow
});
return {
// 數(shù)據(jù)是否下載成功的標(biāo)識(shí)
loaded: false,
dataSource: ds
};
},
// 請(qǐng)求數(shù)據(jù)
getData: function () {
fetch(REQUEST_URL)
.then((response) => {
return response.json();
})
.then((responseData) => {
// 刷新組件匪蟀,重新渲染組件,展示ListView
// 得到新的數(shù)據(jù)宰僧,更新dataSource
this.setState({
loaded: true,
dataSource: this.state.dataSource.cloneWithRows(responseData.movies)
});
})
.catch((error) => {
alert(error);
})
},
render: function () {
// 如果未請(qǐng)求到數(shù)據(jù)材彪,提示“加載等待”頁(yè)面
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}
/>
);
},
// 組件掛載完成 生命周期函數(shù)
componentDidMount: function () {
// 組件掛載后,開始請(qǐng)求數(shù)據(jù)
this.getData();
},
// 等待加載頁(yè)面
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;
運(yùn)行結(jié)果