本教程內容和https://zhiwehu.gitbooks.io/react-native/content/ 同步更新。
使用ListView
在上一節(jié)中庵佣,我們已經通過TextInput將todo item加到了app.state.items
中外厂,本節(jié)將討論如何通過ListView來顯示這些todo items旧蛾。
ListView是React Naitve的一個核心組件赏胚,用于高效率的顯示縱向滾動的可變化數據列表。使用ListView一般需要:
- 創(chuàng)建一個ListView.DataSource又固,并將列表數據填入。我們一般將這個dataSource放在app的state中煤率,這樣當數據變化時仰冠,app會重新渲染ListView。
- 創(chuàng)建一個ListView蝶糯,設置其dataSource屬性為剛剛創(chuàng)建的dataSource洋只,并實現其renderRow方法。
接下來我們通過代碼來實現上面的2點昼捍。
引入ListView
// 引入ListView
import {..., ListView, ...} from "react-native";
創(chuàng)建ListView.DataSource并初始化數據
// 創(chuàng)建ListView.DataSource
// 實現rowHasChanged方法识虚,這里認為只要新老兩條數據不相同即為變化
const ds = new ListView.DataSource({rowHasChanged: (row1, row2) => row1 !== row2});
// 將ListView放在state中,這里使用cloneWithRows方法來從一個空列表克隆數據
this.state = {
...
dataSource: ds.cloneWithRows([])
};
初始化ListView
<ListView
enableEmptySections
dataSource={this.state.dataSource}
renderRow={(item) => {
return (
<View key={item.key}>
<Text>{item.text}</Text>
</View>
)
}}
/>
更新dataSource
我們需要在add item到items的時候妒茬,同時更新dataSource担锤,我們只需要調用this.setState()
方法即可。在app.js的handleAddItem
方法里更新dataSource
handleAddItem() {
...
const newItems = ...
// 更新state
this.setState({
...
dataSource: this.state.dataSource.cloneWithRows(newItems)
});
}
運行結果如下:

使用新的Row組件
為了以后擴展方便乍钻,我們將創(chuàng)建一個新的Row組件肛循,用于顯示ListView中的每一行數據。
row.js
import React, {Component} from "react";
import {View, Text, StyleSheet} from "react-native";
class Row extends Component {
render() {
return (
<View style={styles.container}>
<View style={styles.textWrap}>
<Text style={styles.text}>{this.props.text}</Text>
</View>
</View>
)
}
}
const styles = StyleSheet.create({
container: {
padding: 10,
flexDirection: "row",
flex: 1,
justifyContent: "space-between",
alignItems: "flex-start"
},
textWrap: {
flex: 1,
marginHorizontal: 10
},
text: {
fontSize: 24,
color: "#4d4d4d"
}
});
export default Row;
更新app.js代碼
在app.js里团赁,更新ListView的代碼如下:
// 引入Keyboard
import {View, Text, StyleSheet, Platform, ListView, Keyboard} from "react-native";
// 引入Row
import Row from "./row";
...
<ListView
style={styles.list}
enableEmptySections
dataSource={this.state.dataSource}
onScroll={() => Keyboard.dismiss()}
renderRow={({key, ...value}) => {
return (
<Row
key={key}
{...value}
/>
)
}}
renderSeparator={(sectionId, rowId) => {
return <View key={rowId} style={styles.separator}/>
}}
/>
// ListView的style如下:
...
list: {
backgroundColor: '#FFF'
},
separator: {
borderWidth: 1,
borderColor: "#F5F5F5"
}
...
enableEmptySections育拨,在未來的react native版本中,ListView將默認渲染空section headers欢摄,所以這里設置這個參數熬丧。
onScroll={() => Keyboard.dismiss()}
會在ListView手指滾動的時候,將輸入框隱藏起來怀挠,給用戶更好的體驗
({key, ...value})
使用ES6的...來將item的屬性動態(tài)的傳給Row組件
renderSeparator用于渲染數據行的間隔橫線
再次運行析蝴,是不是感覺樣式更美觀了呢害捕?

待改進的地方
更新dataSource我們可以寫一個通用的方法,這樣以后在增加闷畸、修改尝盼、刪除以及過濾查詢時都可以很方便的調用
/*
一個通用的setSource方法,方便調用
*/
setSource(items, itemsDatasource, otherState = {}) {
this.setState({
items,
dataSource: this.state.dataSource.cloneWithRows(itemsDatasource),
...otherState
})
}
這樣我們只需要在調用這個方法來更新state了。
handleAddItem() {
...
// 更新state
this.setSource(newItems, newItems, {value: ""})
}
本節(jié)代碼:https://github.com/zhiwehu/todo/tree/listview
- React Native實戰(zhàn)開發(fā)1:搭建開發(fā)環(huán)境
- React Native實戰(zhàn)開發(fā)2:布局
- React Native實戰(zhàn)開發(fā)3:模塊劃分
- React Native實戰(zhàn)開發(fā)4:屬性和狀態(tài)
- React Native實戰(zhàn)開發(fā)5:使用TextInput
- React Native實戰(zhàn)開發(fā)6:使用ListView
- React Native實戰(zhàn)開發(fā)7:使用Switch更新todo complete狀態(tài)
- React Native實戰(zhàn)開發(fā)8: 刪除todo item