簡體   English   中英

VirtualizedList:您有一個更新緩慢的大型列表

[英]VirtualizedList: You have a large list that is slow to update

我使用帶有大量項目的 FlatList。 我從 Expo XDE 收到以下警報。

VirtualizedList:您有一個更新緩慢的大型列表 - 確保您的 renderItem function 呈現遵循 React 性能最佳實踐的組件,如 PureComponent、shouldComponentUpdate 等。 {"dt":13861,"prevDt":1498372326027,"contentLength":第6624章

我對我的 FlatList 使用了一些優化方法,例如 PureComponent,但我仍然收到此警報。 在我描述我的優化之前,你能告訴我即使 FlatList 已經優化,這個警報是否總是出現? 或者它可能表明性能存在實際問題? 我問是因為我的 FlatList 的性能很好。

我以前看到過這個錯誤。 優化我的代碼后,我不再看到它。 我通過將 console.log() 語句添加到創建 FlatList 的組件的 render() 函數以及呈現 List 中每個項目的函數來解決問題。 我注意到,每當該頁面上的任何組件(即使是與 FlatList 無關的組件)發生狀態更改時,我的代碼之前都會重新渲染整個 FlatList 及其所有項目。 我通過將各種組件轉換為 PureComponents 來解決這個問題。 這是我的 FlatList 聲明的樣子:

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

請注意,我返回的是一個純組件<Post />

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

  render() { ... }
}

這確保了 FlatList 僅在帖子更改時重新呈現。 當我之前將一個普通函數傳遞給renderItem即一個執行以下操作的函數:

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

我注意到,每當任何項目發生變化時,FlatList 都會重新呈現所有項目。 現在,通過使用 PureComponent,FlatList 僅呈現添加到列表中的新項目(如果列表已被顯示)。

第一次渲染整個列表仍然需要相對較長的時間。 但是, initialNumToRender確保屏幕幾乎立即被填滿(而initialNumToRender項目在后台渲染)。 更重要的是,在初始渲染之后,FlatList 一次只需要渲染一個項目(更改的項目)。

我發現這篇文章很有幫助)。

我剛剛意識到這也解釋here

我注意到這個問題的答案並沒有為那些使用功能組件和鈎子的人提供解決方案。 我遇到了這個問題,我能夠通過使用鈎子“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} />

還要確保不要用 SourceList 封裝 FlatList 對我來說,它偶然出現,因為我使用了 native-base,並且沒有注意到,他們的 Component <Content>替換了 ScrollList。

有關更多信息,請參見此處: https : //stackoverflow.com/a/54512633/1256697

添加 prop initialNumToRender={n} 對我有用(n 是一個相當短的數量,例如 5)

除了給出的所有答案之外,您還可以嘗試將removeClippedSubviews設置為true

<FlatList
  removeClippedSubviews

  // ...other props
/>

如果您正在使用功能組件,將組件包裝在memo是防止不必要的渲染的好方法,而無需經歷將功能組件轉換為純類組件的麻煩。 這篇文章解釋了更多

按照這個例子:

在父組件中:

import React from 'react';
import {FlatList} from 'react-native';
import PostCard from './PostCard';

export const NewsFeeds = props => {
      return (
        <FlatList
          data={data}
          initialNumToRender={4}
          refreshing={loading}
          renderItem={_renderitem}
        />
      );
    };

const _renderitem = ({item}) => <PostCard item={item} />;

在子組件中

import React, {memo} from 'react';
import {View} from 'react-native';

const PostCard = (props) => {
        return (
            <View>
    
            </View>
        );
    };
    
 export default memo(PostCard);

如果您使用的是類組件,請通過擴展React. PureComponent來確保您的組件是純組件React. PureComponent 類定義中的React. PureComponent

class NewsFeeds extends React.PureComponent {
  render() {
    return (
      <FlatList
          data={data}
          initialNumToRender={4}
          refreshing={loading}
          renderItem={_renderitem}
      />
    )
  }
}

導出時將備忘錄添加到您的 renderItem 組件

從“反應”導入反應,{memo}; . . . 你的代碼。 . . 導出默認備忘錄(您的組件名稱);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM