跳到主要內容

最佳化 Flatlist 設定

術語

  • VirtualizedList: FlatList 背後的組件(React Native 對 Virtual List 概念的實作。)

  • 記憶體消耗: 有關您的列表有多少資訊被儲存在記憶體中,這可能會導致應用程式崩潰。

  • 反應速度: 應用程式回應互動的能力。例如,低反應速度是指當您觸摸一個組件時,它會等待一段時間才回應,而不是像預期那樣立即回應。

  • 空白區域:VirtualizedList 無法快速渲染您的項目時,您可能會進入列表的某部分,其中未渲染的組件會顯示為空白空間。

  • Viewport(視口): 渲染成像素內容的可見區域。

  • Window(視窗): 應該掛載項目的區域,通常比視口大得多。

Props(屬性)

以下是可以幫助改善 FlatList 效能的屬性列表

removeClippedSubviews

類型預設值
BooleanFalse

如果為 true,則視口外的視圖將從原生視圖層次結構中分離。

優點: 這減少了花費在主線程上的時間,從而通過將視口外的視圖排除在原生渲染和繪圖遍歷之外,降低了丟幀的風險。

缺點: 請注意,此實作可能存在錯誤,例如內容遺失(主要在 iOS 上觀察到),尤其是當您對變換和/或絕對定位執行複雜操作時。另請注意,這不會節省大量記憶體,因為視圖不會被釋放,只會被分離。

maxToRenderPerBatch

類型預設值
Number10

這是一個 VirtualizedList 屬性,可以通過 FlatList 傳遞。它控制每個批次渲染的項目數量,這是每次滾動時渲染的下一個項目塊。

優點: 設定較大的數字意味著滾動時視覺空白區域較少(提高了填充率)。

缺點: 每個批次項目越多意味著 JavaScript 執行時間越長,可能會阻止其他事件處理(如按下),從而損害反應速度。

updateCellsBatchingPeriod

類型預設值
Number50

雖然 maxToRenderPerBatch 告知每個批次渲染的項目數量,但設定 updateCellsBatchingPeriod 會告知您的 VirtualizedList 批次渲染之間的延遲時間(以毫秒為單位)(您的組件渲染視窗化項目的頻率)。

優點: 將此屬性與 maxToRenderPerBatch 結合使用,您可以靈活地例如在較不頻繁的批次中渲染更多項目,或在更頻繁的批次中渲染更少的項目。

缺點: 較不頻繁的批次可能會導致空白區域,較頻繁的批次可能會導致反應速度問題。

initialNumToRender

類型預設值
Number10

要渲染的初始項目數量。

優點: 為每個設備定義可覆蓋螢幕的精確項目數量。這可以大大提高初始渲染的效能。

缺點: 設定較低的 initialNumToRender 可能會導致空白區域,尤其是在初始渲染時它太小而無法覆蓋視口的情況下。

windowSize

類型預設值
Number21

此處傳遞的數字是一個測量單位,其中 1 等於您的視口高度。預設值為 21(視口上方 10 個,下方 10 個,中間一個)。

優點: 較大的 windowSize 將減少滾動時看到空白空間的機會。另一方面,較小的 windowSize 將導致同時掛載的項目更少,從而節省記憶體。

缺點: 對於較大的 windowSize,您將消耗更多記憶體。對於較小的 windowSize,您將更有可能看到空白區域。

列表項目

以下是有關列表項目組件的一些提示。它們是您列表的核心,因此它們需要快速。

使用基本組件

您的組件越複雜,它們的渲染速度就越慢。盡量避免在您的列表項目中包含大量邏輯和巢狀結構。如果您在您的應用程式中大量重複使用此列表項目組件,請僅為您的大型列表建立一個組件,並盡可能減少邏輯和巢狀結構。

使用輕量組件

您的組件越重,它們的渲染速度就越慢。避免使用大型圖片(對於列表項目,請使用裁剪版本或縮圖,盡可能小)。與您的設計團隊溝通,在您的列表中盡可能少地使用效果、互動和資訊。在您的項目的詳細資訊中顯示它們。

使用 memo()

React.memo() 建立一個記憶化組件,該組件僅在傳遞給組件的屬性發生更改時才會重新渲染。我們可以利用這個函數來最佳化 FlatList 中的組件。

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

const MyListItem = memo(
({title}: {title: string}) => (
<View>
<Text>{title}</Text>
</View>
),
(prevProps, nextProps) => {
return prevProps.title === nextProps.title;
},
);

export default MyListItem;

在這個範例中,我們已確定 MyListItem 應僅在標題更改時重新渲染。我們將比較函數作為第二個參數傳遞給 React.memo(),以便僅在指定的屬性更改時才重新渲染組件。如果比較函數返回 true,則不會重新渲染組件。

使用快取最佳化圖片

您可以使用社群套件(例如來自 @DylanVannreact-native-fast-image)來獲得更高效能的圖片。您列表中的每張圖片都是一個 new Image() 實例。它越快到達 loaded hook,您的 JavaScript 線程就會越快再次空閒。

使用 getItemLayout

如果您的所有列表項目組件都具有相同的高度(或寬度,對於水平列表),則提供 getItemLayout 屬性可以消除您的 FlatList 管理異步佈局計算的需求。這是一種非常理想的最佳化技術。

如果您的組件具有動態大小並且您確實需要效能,請考慮詢問您的設計團隊,他們是否可以考慮重新設計以獲得更好的效能。

使用 keyExtractor 或 key 屬性

您可以為您的 FlatList 組件設定 keyExtractor。此屬性用於快取,並作為 React key 來追蹤項目重新排序。

您也可以在您的項目組件中使用 key 屬性。

避免在 renderItem 上使用匿名函數

對於函數組件,請將 renderItem 函數移到返回的 JSX 之外。此外,請確保將其包裝在 useCallback hook 中,以防止每次渲染時重新建立它。

對於類別組件,請將 renderItem 函數移到 render 函數之外,這樣它就不會在每次調用 render 函數時重新建立自身。

tsx
const renderItem = useCallback(({item}) => (
<View key={item.key}>
<Text>{item.title}</Text>
</View>
), []);

return (
// ...

<FlatList data={items} renderItem={renderItem} />;
// ...
);