React Native中FlatList加载新项时添加按钮卡顿问题
问题描述
- 需求:实现商品列表,点击「添加至购物篮」按钮后,按钮切换为数量计数器供用户选择商品数量。
- 问题:向下滚动FlatList加载新项时,绿色添加按钮会卡顿1秒左右才切换为计数器。

相关代码
FlatList代码
<FlatList data={products} renderItem={renderPrices} numColumns={1} keyExtractor={(item, index) => index.toString()} refreshControl={ <RefreshControl refreshing={refreshing} onRefresh={onRefresh} /> } ListFooterComponent={() => loading ? ( <View style={styles.spinnerContainer}> <Spinner size="giant" /> </View> ) : !productStore.moreItems ? ( <View style={{ justifyContent: 'center', alignItems: 'center', paddingVertical: 20, backgroundColor: Colors.secondary500, marginHorizontal: 3 }}> {IconComponent(evaIcons.done, Colors.black900, { width: 30, height: 30 })} <Text>سلات قائمة ديل منتجات</Text> </View> ) : null } nestedScrollEnabled={true} onEndReached={() => getProductList()} onEndReachedThreshold={0.5} />
商品列表项组件代码
return ( <Layout style={styles.container}> <View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}> <Image source={{ uri: image }} resizeMode="contain" style={{ width: 100, height: 70 }} /> <View style={styles.priceContainer}> <Text style={styles.priceText}>{price.price}</Text> <Text style={styles.currencyText}>دم</Text> </View> <PriceType quantityType={ price.sellUnit === SellUnitEnum.ATOMIC ? price.atomicRtlName : price.packingRtlName } /> </View> <View style={{ flex: 3 }}> <View style={{ flex: 1, flexDirection: "row-reverse", justifyContent: "space-between", alignItems: "center", }} > <Text style={{ width: "75%", textAlign: "right", fontFamily: "almarai-bold", marginRight: 3, }} > {price.rtlName} </Text> <AwalPoint points={price.points} backgroundColor={Colors.gray200} textColor={Colors.gray800} /> </View> <View style={{ flex: 1, flexDirection: "row-reverse" }}> <PackageQuantity title={price.atomicRtlName.toString() + " في"} packageName={price.packingRtlName} quantity={price.packageQuantity.toString()} image={require("../assets/surprise.png")} backgroundColor={Colors.primary400} containerStyle={{ flex: 1 }} /> <PackageQuantity title="تمن" packageName={ price.sellUnit === "ATOMIC" ? price.packingRtlName : price.atomicRtlName } quantity={ (price.sellUnit === "ATOMIC" ? (price.price * price.packageQuantity).toFixed(2) : (price.price / price.packageQuantity).toFixed(2) ).toString() + " دم" } image={require("../assets/dollar.png")} backgroundColor={Colors.secondary400} containerStyle={{ flex: 1.5 }} /> </View> <View style={{ flex: 1, flexDirection: "row", paddingBottom: 7 }}> {basketItem === undefined && !isFocused ? ( <Button style={{ height: 45, borderWidth: 0, borderRadius: 100, backgroundColor: Colors.secondary500, }} onPress={() => { console.log("button clicked: "); useDispatch(updateItems({ item: price, quantity: 1, error: undefined, productImage: image })); }} accessoryRight={IconComponent(evaIcons.cart, Colors.white500)} > {(props) => ( <Text {...props} style={{ fontFamily: "almarai-bold", fontSize: 15, color: Colors.white500, }} > أضف إلى السلة </Text> )} </Button> ) : ( <CounterInput style={{ flex: 1 }} priceId={price.id} isFocused={isFocused} setIsFocused={setIsFocused} maxValue={price.storeQuantity} buttonStyle={{ backgroundColor: Colors.primary500, borderWidth: 0 }} /> )} <View style={{ flex: 1, justifyContent: 'center', alignItems: 'flex-end' }}> {(price.isDiscountable === true) ? <View style={{ flexDirection: 'row-reverse', justifyContent: 'center', alignItems: 'center' }}> <Image source={require("../assets/promo.png")} resizeMode="contain" style={{ width: 30, height: 30 }} /> <Text style={{ textAlign: 'center', fontFamily: 'almarai-regular' }}>فيه روميز</Text> </View> : null} </View> </View> </View> </Layout> );
解决方案建议
- 替换
keyExtractor:不要用index作为列表项的key,改用商品的唯一标识(比如price.id),避免FlatList复用组件时因index变化导致状态错乱:keyExtractor={(item) => item.id.toString()} - 优化组件重渲染:用
React.memo包裹商品列表项组件,减少不必要的重渲染:const ProductItem = React.memo(({ price, image, basketItem, isFocused, setIsFocused }) => { // 组件原有代码 }); - 状态判断优化:确保
basketItem的判断基于稳定的数据源(比如从Redux直接根据price.id查询),避免依赖延迟更新的props。 - FlatList性能配置:添加以下属性提升滚动和加载性能:
removeClippedSubviews={true} // 移除不可见区域的组件 windowSize={5} // 控制预渲染的列表项数量,减少内存占用 maxToRenderPerBatch={10} // 每次批量渲染的项数 - 提取
ListFooterComponent:不要在render中动态创建Footer组件,抽成单独的组件避免重复创建:const ListFooter = () => { // 原有Footer逻辑 }; // 然后在FlatList中使用 ListFooterComponent={<ListFooter />}
内容的提问来源于stack exchange,提问作者DarkSide77
相关产品推荐
相关产品推荐

