此文是我的出版書籍[《React Native 精解與實戰》](http://rn.parryqiu.com/)連載分享,此書由機械工業出版社出版,書中詳解了 React Native 框架底層原理、React Native 組件佈局、組件與 API 的介紹與代碼實戰,以及 React Native... ...
此文是我的出版書籍《React Native 精解與實戰》連載分享,此書由機械工業出版社出版,書中詳解了 React Native 框架底層原理、React Native 組件佈局、組件與 API 的介紹與代碼實戰,以及 React Native 與 iOS、Android 平臺的混合開發底層原理講解與代碼實戰演示,精選了大量實例代碼,方便讀者快速學習。
書籍還配套了視頻教程「80 節實戰課精通 React Native 開發」,此視頻課程建議配合書籍學習,書籍中原理性的東西講解的比較清晰,而視頻教程對於組件、API 等部分的代碼實戰開發講解比較直觀。
書籍相關所有資料請訪問:http://rn.parryqiu.com
8.4 React Native 網路請求與列表綁定方案
下麵我們就通過結合 Fetch API 以及 React Native 框架中的列表組件,通過代碼實戰的形式進行這兩個重要知識點的學習。
首先我們數據獲取使用豆瓣的公開 API,獲取目前正在上映的 20 部電影的信息,豆瓣 API 地址為:https://api.douban.com/v2/movie/in_theaters?count=20,API 介面返回的 JSON 數據如圖 8-6 所示。
圖 8-6 豆瓣 API 返回的 JSON 數據
在此示例代碼中,將採用組件開發的思想,首頁載入 4 個 Tab,每一個 Tab 載入對應的頁面組件。這裡的列表載入在第一個 Tab 中,組件定義為 Home,在項目中建立的文件名為 home.js。
完整代碼在本書配套源碼的 08-03 文件夾。
1. /**
2. * 章節: 08-03
3. * App.js 定義了項目的大結構,使用 4 個 Tab 進行佈局。
4. * FilePath: /08-03/ListDemo/App.js
5. * @Parry
6. */
7.
8. import React, {Component} from 'react';
9. import {Platform, StyleSheet, Text, View, Image} from 'react-native';
10. import TabNavigator from 'react-native-tab-navigator';
11. import HomePage from './home';
12.
13. export default class App extends Component < {} > {
14.
15. state = {
16. selectedTab: 'home'
17. };
18.
19. _renderContent = (color : string, index : string) => {
20. switch (index) {
21. case "home":
22. return (<HomePage/>);
23. }
24. };
25.
26. render() {
27. return (
28. <TabNavigator>
29. <TabNavigator.Item
30. selected={this.state.selectedTab === 'home'}
31. title="首頁"
32. renderIcon={() => <Image
33. style= { {
34. width: 25,
35. height: 25
36. } } />
37. source={require('./flux.png')}/>}
38. renderSelectedIcon={() => <Image
39. style= { {
40. width: 25,
41. height: 25
42. } } />
43. source={require('./relay.png')}/>}
44. onPress={() => this.setState({selectedTab: 'home'})}>
45. {this._renderContent('#FFFFFF', 'home')}
46. </TabNavigator.Item>
47.
48. ...... //此處省略了其他三個 Tab 的定義
49. //完整代碼在書籍的配套源碼中
50.
51. </TabNavigator>
52. );
53. }
54. }
上面這段代碼為 App.js 的部分主要邏輯,註意在代碼的第 11 行導入外部 Home 組件的方法,以及針對之前 Tab 組件章節的邏輯修改了載入對應組件的方法,主要為代碼第 20 行的部分。
1. /**
2. * 章節: 08-03
3. * home.js 定義了第一個 Tab 載入的頁面組件,用於載入豆瓣電影列表
4. * 同時演示了 ListView 綁定方法
5. * FilePath: /08-03/ListDemo/home.js
6. * @Parry
7. */
8.
9. import React, {Component} from 'react';
10. import {
11. Platform,
12. StyleSheet,
13. Text,
14. View,
15. Image,
16. ListView,
17. SafeAreaView
18. } from 'react-native';
19.
20. export default class HomePage extends Component < {} > {
21.
22. constructor(props) {
23. super(props);
24. this.state = {
25. dataSource: new ListView.DataSource({ //定義數據源
26. rowHasChanged: (row1, row2) => row1 !== row2
27. }),
28. loaded: false
29. };
30. }
31.
32. componentDidMount() {
33. this.fetchData(); //開始請求數據
34. };
35.
36. fetchData() {
37. fetch("https://api.douban.com/v2/movie/in_theaters").then((response) => response.json()).then((responseData) => {
38. this.setState({
39. dataSource: this
40. .state
41. .dataSource
42. .cloneWithRows(responseData.subjects), //讀取返回的所有電影數據
43. loaded: true
44. });
45. }).done();
46. };
47.
48. render() {
49. return (
50. <View style={styles.container}>
51. <ListView automaticallyAdjustContentInsets={false} //此選項可以修複掉會自動多出來的大約 10px 的空行
52. dataSource={this.state.dataSource} renderRow={this._renderRow}/>
53. </View>
54. );
55. };
56.
57. _renderRow(rowData, sectionID, rowID) {
58. return (
59. <SafeAreaView>
60. <View style={styles.row}>
61. <Image
62. style={styles.thumb}
63. source= { {
64. uri: rowData.images.large
65. } } />
66. <View style={styles.texts}>
67. <Text style={styles.textTitle}>
68. {rowData.title}
69. </Text>
70. <Text style={styles.textTitle}>
71. 年份: {rowData.year}
72. </Text>
73. <Text style={styles.textTitle}>
74. 豆瓣評分: {rowData.rating.average}
75. </Text>
76. </View>
77. </View>
78. <View style={styles.separator}/>
79. </SafeAreaView>
80. );
81. };
82. }
83.
84. var styles = StyleSheet.create({
85. container: {
86. flex: 1
87. },
88. row: {
89. flexDirection: 'row',
90. padding: 10
91. },
92. separator: {
93. height: 1,
94. backgroundColor: '#EEEEEE'
95. },
96. thumb: {
97. width: 60,
98. height: 80,
99. borderRadius: 2
100. },
101. textTitle: {
102. flex: 1,
103. textAlign: "left",
104. paddingLeft: 10,
105. fontWeight: "bold",
106. flexDirection: 'row',
107. color: "#666666"
108. },
109. texts:{
110. flexDirection: 'column',
111. paddingTop: 5
112. }
113. });
上面代碼為 Home 組件的實現方法,下麵主要對代碼中的一些重要邏輯作一些說明:
代碼在 17 行導入了一個新的 View 組件,SafeAreaView 用於在 iPhone X 下佈局 View 而控制整個 View 安全佈局於手機的可視區域中;
代碼的第 25 - 27 行,定義了 ListView 的數據源,同時定義了 rowHasChanged 的邏輯;
代碼第 32 行在生命周期 componentDidMount 中定義了從 API 中載入數據的方法;
代碼第 36 - 46 行定義了從豆瓣 API 使用 Fetch API 請求數據的方法,註意對 Fetch API 返回的 Promise 對象的處理方法;
代碼第 51 行定義了 ListView 綁定的方法,行渲染的方法為代碼中第 57 行定義的方法 _renderRow;
代碼第 57 - 81 行定義了列表渲染的方法,使用 View 與 Text 組件進行了列表的展示佈局;
後續的樣式定義如之前學習的樣式定義一樣,進行精細佈局控制即可。
項目運行在 iOS 平臺的效果如圖 8-7 所示,Android 平臺大家也可以直接下載本書配套源碼在本地學習、測試與運行。
圖 8-7 iOS 下的 ListView 運行效果
8.5 本章小結
列表綁定是 App 開發最常用的一個開發功能,你可以隨手打開自己手機上的 App 就會發現許多 App 的首頁都是進行了數據請求、列表綁定或列表數據刷新等動作,這也真是移動互聯網的魅力所在,用戶可以隨時獲取到最新的資訊信息。所以此章節是一個重要的章節,並從底層知識點到實戰代碼都進行了詳細地講解與演示,希望能幫助你開發出你的 App 的首頁列表組件。