自学React-native (第五天)-- FlatList
自学React-native (第五天)-- FlatList
1.前言
FlatList是facebook公司用来替代ViewList控件的新组件。为什么选择FlatList呢?因为相比ViewList的全渲染机制,FlatList更省资源,卡顿和OOD的几率小。具体执行上的机制是类似走马灯,处于屏幕外的item部分不会全部显示而会由白屏取代以节省资源,所以FlatList有个问题就是组件本身并不保存状态。
本次学习中使用其他控件:
- RefreshControl 。此控件配合FlatList的refreshControl属性可以自定义上拉刷新栏,修改菊花颜色、提示文案、展示高度等等。
- ActivityIndicator。可以自定义的菊花控件,多用于下拉刷新中,方便用户自定义菊花样式。
2.实现代码
import React from "react";
import {
View,
Text,
Button,
FlatList,
StyleSheet,
RefreshControl,
ActivityIndicator,
TextInput
} from "react-native";
const CITYS = ["武汉", "重庆", "北京", "上海"];
export default class FlatListDemo extends React.Component {
constructor(props) {
super(props);
this.state = {
isLoading: false,
dataArray: CITYS,
isEndReachedLoading:false
};
}
_renderItem(data) {
return (
<View style={styles.item}>
<Text style={styles.text}>{data.item}</Text>
<TextInput />
</View>
);
}
_genIndicator(){
return <View style={styles.indicatorContainer}>
<ActivityIndicator
size={"large"}
animating={this.state.isEndReachedLoading}
color={"red"}
/>
<Text style={styles.indicator}>正在加载更多</Text>
</View>
}
//下拉刷新
_onEndReachedloadData(){
this.setState({
isEndReachedLoading:true
});
setTimeout(()=>{
CITYS.push(Date.now());
this.setState({
isEndReachedLoading:false,
dataArray:CITYS
});
},2000);
}
//加载数据
loadData() {
this.setState({
isLoading: true
});
setTimeout(() => {
let ReversCitys = CITYS.reverse();
this.setState({
CITYS: ReversCitys,
isLoading: false
});
}, 2000);
}
render() {
return (
<View style={styles.container}>
<FlatList
data={CITYS}
renderItem={data => {
return this._renderItem(data);
}}
refreshControl={
<RefreshControl
title={"loading"}
colors={["red"]}
refreshing={this.state.isLoading}
onRefresh={() => {
this.loadData();
}}
/>
}
ListFooterComponent={
()=>this._genIndicator()
}
onEndReached={
()=>{
this._onEndReachedloadData();
}
}
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: "center",
// alignItems:"center",
backgroundColor: "#789"
},
item: {
backgroundColor: "#169",
height: 200,
marginRight: 15,
marginLeft: 15,
marginBottom: 15,
alignItems: "center",
justifyContent: "center"
},
text: {
color: "white",
fontSize: 20
},
indicatorContainer:{
alignItems:"center",
justifyContent:"center"
},
indicator:{
color:"red",
margin:10
}
});
其中实现了自定义的上部刷新组件,其实FLatList默认是提供了刷新机制和组件,如果你对自定义要求不高可以直接使用默认的控件节省时间:
render() {
//refreshing 是否显示菊花loading图标
//onRefresh 当下拉刷新时触发,一般在这里处理拉取数据的功能
return (
<View style={styles.container}>
<FlatList
data={CITYS}
renderItem={data => {
return this._renderItem(data);
}}
refreshing={this.state.isLoading}
onRefresh={() => {
this.loadData();
}}
/>
</View>
);
}
}
3.性能优化
在RN文档中给出了一个优化方式,使用PureCompoent替代原来继承的Component来进行浅比较以减少不必要的render(其实这种方式不能100%解决多余render的问题,但是能减少60%左右的无谓操作,根据28原则PureComponent是有必要使用的)
1. render内部function bind优化:
FlatList内部的方法不要使用function.bind()方式,因为每次render的时候都会创建一个新的方法(注意bind方法),这是一个很大的资源浪费,当这类方法多了以后会出现卡顿。解决方案:
- 在constructor中使用bind。此时只需绑定一次,以后都使用这个bind后的方法,所以不会有额外的消耗。
- 使用箭头函数。 箭头函数将class的作用域绑定到函数中。而调用this.xxx是不会再创建一个新的function的。
2. 使用PureComponent
这个优化的场景一般是编写自定义组件时需要用到,此时父组件render时,子组件也会重新render,而使用pureComponent则可以很大程度上避免这个行为。不过需要注意的是由于PureComponent使用了浅比较所以如果传入子组件的参数是传名引用的话会出现子组件无变化的问题,此时需要变换对应参数的引用地址来解决这个问题。比如一个数组我们这么处理:
this.state.dataArray.push(Date.now().toString());
this.setState({
dataArray:this.state.dataArray.concat([])
});
来生成一个新的引用地址来触发子组件更新。当然你也可以使用immutabledata:
immutable.List([1,2,3,4,5])
4, 结语
FlatList是个利器,大家如果以前使用的是ViewList最好平稳过渡到FlatList这样能极大提升效率。