FlatList是我们项目中经常使用的一个组件,
下面简述下使用中要注意的问题
一、keyExtractor
keyExtractor的唯一性
/** * Used to extract a unique key for a given item at the specified index. Key is used for caching * and as the react key to track item re-ordering. The default extractor checks `item.key`, then * falls back to using the index, like React does. */ keyExtractor?: (item: ItemT, index: number) => string;
/**
*用于在指定索引处提取给定项的唯一键。密钥用于缓存
*并作为跟踪项目重新订购的反应键。默认提取器检查'item.key',然后
*退回到使用索引,就像React一样。
*/
keyExtractor决定了子组件是否需要新建。只要有新的keyExtractor,那么就会构造新的子组件。
所以我们需要确保keyExtractor的唯一性,如果keyExtractor不唯一,就会出现莫名其妙的错误
一般我们有以下两种方式设置keyExtractor
1、依赖当前数据模型的唯一标记userId(此方案需要后台返回的数据ID是唯一的)
keyExtractor={(item)=>item.userId}
2、前端自己生成
let extraUniqueKey = () => Math.random().toString();
二、renderItem、ListHeaderComponent
renderItem、ListHeaderComponent组件封装成函数时,注意this的绑定,
如果不想考虑this的问题,建议直接使用箭头函数
详情参考:React Native bind函数
先看效果:
代码如下:
1、使用箭头函数(推荐)
private showFlatList() { let dataList = this.props.listData if (dataList && dataList.length) { let extraUniqueKey = () => Math.random().toString(); return ( <FlatList style={{ backgroundColor: '#ffffff', height: (44 * (dataList.length > 5 ? 4 : dataList.length) + 44), marginHorizontal: 15, marginTop: 20, }} data={dataList} renderItem={this.renderUserItem()} // keyExtractor={(item)=>item.userId} keyExtractor={extraUniqueKey} ListHeaderComponent={this.listHeaderView()} showsVerticalScrollIndicator={false} /> ); } } // 表头(箭头函数) listHeaderView = () => { return ( <View style={{ backgroundColor: '#E7F1FF', height: 44, flexDirection: 'row', justifyContent: 'space-around', alignItems: 'center', }}> <Text style={style.itemText}>{this.showStr()}</Text> <Text style={style.itemText}>来来来 </Text> </View>) } // 表格 (箭头函数) renderUserItem = (renderItem: ListRenderItemInfo<NotEvaUserModel>) => { let item: NotEvaUserModel = renderItem.item return ( <View style={style.itemBg}> <Text style={style.itemText}>{this.showStr()}</Text> <Text style={style.itemText}>{item.userName}</Text> </View> ) } showStr() { return '我是showStr函数' }
2、使用普通函数,且renderItem、ListHeaderComponent中使用到this
实际验证renderUserItem必须绑定this,listHeaderView不绑定this也可以
所以这就是普通函数的不方便之处,严谨方法就是不论是不是需要都绑定this,如果不想这样就是出错了再绑定或者换箭头函数
private showFlatList() { let dataList = this.props.listData if (dataList && dataList.length) { let extraUniqueKey = () => Math.random().toString(); return ( <FlatList style={{ backgroundColor: '#ffffff', height: (44 * (dataList.length > 5 ? 4 : dataList.length) + 44), marginHorizontal: 15, marginTop: 20, }} data={dataList} renderItem={this.renderUserItem.bind(this)} // keyExtractor={(item)=>item.userId} keyExtractor={extraUniqueKey} ListHeaderComponent={this.listHeaderView()} showsVerticalScrollIndicator={false} /> ); } } // 表头(普通函数) listHeaderView () { return ( <View style={{ backgroundColor: '#E7F1FF', height: 44, flexDirection: 'row', justifyContent: 'space-around', alignItems: 'center', }}> <Text style={style.itemText}>{this.showStr()}</Text> <Text style={style.itemText}>来来来 </Text> </View>) } // 表格 (普通函数) renderUserItem (renderItem: ListRenderItemInfo<NotEvaUserModel>) { let item: NotEvaUserModel = renderItem.item return ( <View style={style.itemBg}> <Text style={style.itemText}>{this.showStr()}</Text> <Text style={style.itemText}>{item.userName}</Text> </View> ) } showStr() { return '我是showStr函数' }
3、使用普通函数,且renderItem、ListHeaderComponent中未使用到this
不用考虑this绑定的情况
private showFlatList() { let dataList = this.props.listData if (dataList && dataList.length) { let extraUniqueKey = () => Math.random().toString(); return ( <FlatList style={{ backgroundColor: '#ffffff', height: (44 * (dataList.length > 5 ? 4 : dataList.length) + 44), marginHorizontal: 15, marginTop: 20, }} data={dataList} renderItem={this.renderUserItem()} // keyExtractor={(item)=>item.userId} keyExtractor={extraUniqueKey} ListHeaderComponent={this.listHeaderView()} showsVerticalScrollIndicator={false} /> ); } } // 表头(普通函数) listHeaderView () { return ( <View style={{ backgroundColor: '#E7F1FF', height: 44, flexDirection: 'row', justifyContent: 'space-around', alignItems: 'center', }}> <Text style={style.itemText}>我是showStr函数</Text> <Text style={style.itemText}>来来来 </Text> </View>) } // 表格 (普通函数) renderUserItem (renderItem: ListRenderItemInfo<NotEvaUserModel>) { let item: NotEvaUserModel = renderItem.item return ( <View style={style.itemBg}> <Text style={style.itemText}>我是showStr函数</Text> <Text style={style.itemText}>{item.userName}</Text> </View> ) } } const style = StyleSheet.create({ bg: { backgroundColor: '#FFFFFF', borderRadius: 10, width: DeviceHelp.screenW - 100, }, toptext: { fontWeight: 'bold', color: '#333333', marginTop: 20, textAlign: 'center', fontSize: DeviceHelp.fontSize(17) }, centerText: { color: '#505A82', paddingTop: 15, paddingLeft: 15, paddingRight: 15, fontSize: DeviceHelp.fontSize(15) }, itemBg: { height: 44, flexDirection: 'row', justifyContent: 'space-around', alignItems: 'center', backgroundColor: "#EFEFEF", }, itemText: { color: '#333333', fontSize: DeviceHelp.fontSize(15), }, line: { marginTop: 20, backgroundColor: '#99999955', height: 1, }, btnText: { marginTop: 15, marginBottom: 15, color: "#3498FE", fontWeight: "bold", textAlign: "center", fontSize: DeviceHelp.fontSize(18), }, })
备注:
函数(不论普通函数还是箭头函数)调用时添加不添加()都可以(某些情况下不添加()调用会出问题),
如果是有参数的函数,写()就必须要传入参数,要不就是不写
所以严谨的做法就是我们调用函数时要添加(),如果还是出错我们可以尝试添加.bind(this)