提问者:小点点

虚拟列表:你有一个更新很慢的大列表


我使用FlatList与大量的项目。我收到了来自XDE博览会的警报。

VirtualizedList:您有一个更新缓慢的大型列表-请确保renderItem函数呈现符合React性能最佳实践的组件,如PureComponent、shouldComponentUpdate等。{“dt”:13861,“prevDt”:149832326027,“contentLength”:6624}

我对我的FlatList使用了一些优化方法,例如PureComponent,但我仍然会收到此警报。在我描述我的优化之前,你能告诉我即使FlatList优化了,这个警报是否总是出现吗?或者它表明了性能的实际问题?我问是因为我的FlatList的性能很好。


共3个答案

匿名用户

我以前看到过这个错误。优化我的代码后,我不再看到它。我通过将console.log()语句添加到创建FlatList的组件的呈现()函数以及呈现List中每个项的函数来解决问题。我注意到,每当页面上的任何组件(甚至与FlatList无关的组件)发生状态更改时,我的代码都会重新呈现整个FlatList及其所有项。我通过将各种组件转换为PureComponents来修复此问题。以下是我的FlatList声明:

<FlatList
    ref={(ref) => { this.flatListRef = ref; }}
    data={allPosts}
    initialNumToRender={7}
    renderItem={({ item }) =>
      <Post postJson={item} isGroupAdmin={isGroupAdmin} user={user} />
    }
  />

请注意,我正在返回

import React, { PureComponent } from 'react';
class Post extends PureComponent {

  render() { ... }
}

这确保了FlatList仅在帖子更改时才重新呈现。当我之前传递一个普通的函数到renderItem,即一个函数,做这样的事情:

return (
  <View>
  ...
  </View>
);

我注意到,每当任何项目发生更改时,平面列表都会重新呈现所有项目。现在,通过使用PureComponent,FlatList只呈现添加到列表中的新项目(如果列表已经显示)。

第一次渲染整个列表仍然需要相对较长的时间。但是,initialNumToRender确保屏幕几乎是在瞬间填满的(而剩余的项目则在后台渲染)。更重要的是,在初始渲染之后,平面列表每次只需渲染一个项目(更改的项目)。

我发现这篇文章很有帮助)。

我刚刚意识到这里也解释了这一点

匿名用户

我注意到这个问题的答案并没有为那些使用功能组件和挂钩的人提供解决方案。我遇到了这个问题,通过使用钩子“useMemo()”可以解决它

<FlatList
                keyExtractor={keyExtractor}
                data={productsState.products}
                renderItem={renderItem}
            />
const renderItem = ({ item }) => (
            <ListItem
                title={item.ProductName}
                subtitle={(item.ProductQuantity) + " " + (item.QuantityType !== 
                null ? item.QuantityType : " ") }
                bottomDivider
                topDivider
                chevron
                checkmark={checkMark}
                onLongPress={() => setCheckMark(!checkMark)}
                rightSubtitle={(item.Currency !== null ? item.Currency: " " ) + 
                " " + (item.productCost !== null ? item.productCost: " " )}
                rightSubtitleStyle={{ marginTop: -20 }}
                badge={{ value: item.sellingPrice, textStyle: { color: 'orange' }, containerStyle: { marginTop: -20 } }}
            />
        )

renderItem函数是一个昂贵的计算,因为它需要呈现一个很长的列表。相反,我把它记下来如下

            const memoizedValue = useMemo(() => renderItem, [productsState.product]);

<FlatList
                keyExtractor={keyExtractor}
                data={productsState.products}
                renderItem={memoizedValue}
            />
const renderItem = ({ item }) => (
        <ListItem
            title={item.ProductName}
            subtitle={(item.ProductQuantity) + " " + (item.QuantityType !== 
            null ? item.QuantityType : " ") }
            bottomDivider
            topDivider
            chevron
            checkmark={checkMark}
            onLongPress={() => setCheckMark(!checkMark)}
            rightSubtitle={(item.Currency !== null ? item.Currency: " " ) + 
            " " + (item.productCost !== null ? item.productCost: " " )}
            rightSubtitleStyle={{ marginTop: -20 }}
            badge={{ value: item.sellingPrice, textStyle: { color: 'orange' }, containerStyle: { marginTop: -20 } }}
        />
    )

不要忘记从react导入useMemo,以使其正常工作。

祝你好运

匿名用户

我明白了,为什么会发生这个错误。主要的问题是,当您的onEndReached事件发生时,我确信您正在从服务器加载某些内容,这意味着,您需要等待从服务器加载完成,然后才能调用onEndReached事件。

但在您的例子中,有对onEndReached事件的多重调用。所以,当这种情况发生时,您的应用程序一次又一次地尝试从服务器加载数据。

好了,如何解决这个问题:你需要创建新的状态,例如这是通过分页实现无限滚动。

const [loader, setLoader] = useState<boolean>(false);

const onEndReached = (page) => {
  if (next && !loader) {
    setPage(page + 1)
  }
}

const loadData = async () => {
  setLoader(true);
  const resp = await getData();
  setLoader(false);
}

<FlatList ...someprops onEndReached={onEndReached} />