React Native FlatList


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 (
            {{
                backgroundColor: '#E7F1FF',
                height: 44,
                flexDirection: 'row',
                justifyContent: 'space-around',
                alignItems: 'center',
            }}>

                {this.showStr()}
                来来来 

            )
    }

    // 表格 (箭头函数)
    renderUserItem = (renderItem: ListRenderItemInfo) => {
        let item: NotEvaUserModel = renderItem.item
        return (
            
                {this.showStr()}
                {item.userName}
            
        )
    }

    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 (
            {{
                backgroundColor: '#E7F1FF',
                height: 44,
                flexDirection: 'row',
                justifyContent: 'space-around',
                alignItems: 'center',
            }}>

                {this.showStr()}
                来来来 

            )
    }

    // 表格 (普通函数)
    renderUserItem (renderItem: ListRenderItemInfo) {
        let item: NotEvaUserModel = renderItem.item
        return (
            
                {this.showStr()}
                {item.userName}
            
        )
    }

    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 (
            {{
                backgroundColor: '#E7F1FF',
                height: 44,
                flexDirection: 'row',
                justifyContent: 'space-around',
                alignItems: 'center',
            }}>

                我是showStr函数
                来来来 

            )
    }

    // 表格 (普通函数)
    renderUserItem (renderItem: ListRenderItemInfo) {
        let item: NotEvaUserModel = renderItem.item
        return (
            
                我是showStr函数
                {item.userName}
            
        )
    }

}

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)