Flatlist の設定の最適化
用語
-
VirtualizedList:
FlatList
の背後にあるコンポーネント (React Native によるVirtual List
の概念の実装)。 -
メモリ消費量: リストに関する情報がどれだけメモリに保存されているか。アプリのクラッシュにつながる可能性があります。
-
応答性: インタラクションに応答するアプリケーションの能力。たとえば、コンポーネントをタッチすると、期待どおりにすぐに応答するのではなく、少し待ってから応答する場合は、応答性が低いといえます。
-
空白領域:
VirtualizedList
がアイテムを十分に速くレンダリングできない場合、レンダリングされていないコンポーネントが空白として表示されるリストの一部に遭遇する可能性があります。 -
ビューポート: ピクセルにレンダリングされるコンテンツの可視領域。
-
ウィンドウ: アイテムがマウントされる領域。一般的にビューポートよりもはるかに大きいです。
プロパティ
FlatList
のパフォーマンス向上に役立つプロパティの一覧を次に示します。
removeClippedSubviews
型 | デフォルト |
---|---|
ブール値 | False |
true
の場合、ビューポートの外にあるビューはネイティブビュー階層から切り離されます。
メリット: これにより、ビューポートの外にあるビューをネイティブレンダリングおよび描画トラバーサルから除外することで、メインスレッドで費やされる時間が短縮され、フレームがドロップするリスクが軽減されます。
デメリット: この実装には、コンテンツの欠落 (主に iOS で観察される) など、バグがある可能性があることに注意してください。特に、変換や絶対配置で複雑な処理を行っている場合は注意が必要です。また、ビューが解放されるわけではなく、単に切り離されるだけなので、これはメモリを大幅に節約するわけではないことにも注意してください。
maxToRenderPerBatch
型 | デフォルト |
---|---|
数値 | 10 |
FlatList
を介して渡すことができる VirtualizedList
プロパティです。これにより、バッチごとにレンダリングされるアイテムの量 (スクロールごとにレンダリングされる次のアイテムの塊) を制御します。
メリット: 大きい数値を設定すると、スクロール時の視覚的な空白領域が少なくなります (塗りつぶし率が向上します)。
デメリット: バッチごとのアイテム数が多いと、JavaScript の実行時間が長くなり、プレスなどの他のイベント処理がブロックされ、応答性が低下する可能性があります。
updateCellsBatchingPeriod
型 | デフォルト |
---|---|
数値 | 50 |
maxToRenderPerBatch
はバッチごとにレンダリングされるアイテムの量を指定しますが、updateCellsBatchingPeriod
を設定すると、バッチレンダリング間の遅延 (ミリ秒単位) を VirtualizedList
に指示します (コンポーネントがウィンドウ化されたアイテムをレンダリングする頻度)。
メリット: このプロパティと maxToRenderPerBatch
を組み合わせることで、たとえば、より少ない頻度のバッチでより多くのアイテムをレンダリングしたり、より頻度の高いバッチでより少ないアイテムをレンダリングしたりすることができます。
デメリット: バッチの頻度が少ないと空白領域が発生する可能性があり、バッチの頻度が高いと応答性の問題が発生する可能性があります。
initialNumToRender
型 | デフォルト |
---|---|
数値 | 10 |
初期レンダリングするアイテムの数。
メリット: すべてのデバイスで画面をカバーするアイテムの正確な数を定義します。これは、初期レンダリングのパフォーマンスを大幅に向上させる可能性があります。
デメリット: initialNumToRender
を低く設定すると、特に初期レンダリングでビューポートをカバーするのに小さすぎる場合は、空白領域が発生する可能性があります。
windowSize
型 | デフォルト |
---|---|
数値 | 21 |
ここで渡される数値は測定単位であり、1 はビューポートの高さに相当します。デフォルト値は 21 です (上下に 10 個のビューポートと、その間の 1 つのビューポート)。
メリット: windowSize
が大きいほど、スクロール中に空白が表示される可能性が低くなります。一方、windowSize
が小さいほど、同時にマウントされるアイテム数が少なくなり、メモリを節約できます。
デメリット: windowSize
が大きいほど、メモリ消費量が多くなります。windowSize
が小さいほど、空白領域が表示される可能性が高くなります。
リストアイテム
以下に、リストアイテムコンポーネントに関するヒントをいくつか示します。これらはリストの中核であるため、高速である必要があります。
基本コンポーネントを使用する
コンポーネントが複雑であるほど、レンダリングが遅くなります。リストアイテムで多くのロジックやネストを避けるようにしてください。このリストアイテムコンポーネントをアプリで多く再利用する場合は、大きなリスト専用のコンポーネントを作成し、できるだけロジックとネストを少なくしてください。
軽量コンポーネントを使用する
コンポーネントが重いほど、レンダリングが遅くなります。重い画像は避けてください (リストアイテムには、可能な限り小さく、切り抜いたバージョンまたはサムネイルを使用してください)。デザインチームと話し合い、リストではできるだけエフェクト、インタラクション、情報を使わないようにしてください。アイテムの詳細に表示してください。
memo()
を使用する
React.memo()
は、コンポーネントに渡された props が変更された場合にのみ再レンダリングされるメモ化されたコンポーネントを作成します。この関数を使用して、FlatList のコンポーネントを最適化できます。
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 が title が変更された場合にのみ再レンダリングされるように決定しました。指定された prop が変更された場合にのみコンポーネントが再レンダリングされるように、比較関数を React.memo() の 2 番目の引数として渡しました。比較関数が true を返すと、コンポーネントは再レンダリングされません。
キャッシュされた最適化された画像を使用する
コミュニティパッケージ (react-native-fast-image (by @DylanVann) など) を使用して、パフォーマンスの高い画像を実現できます。リスト内のすべての画像は new Image()
インスタンスです。loaded
フックに到達するのが速いほど、JavaScript スレッドはより早く解放されます。
getItemLayout を使用する
すべてのリストアイテムコンポーネントの高さ (または水平リストの場合は幅) が同じ場合、getItemLayout プロパティを指定すると、FlatList
が非同期レイアウト計算を管理する必要がなくなります。これは非常に望ましい最適化手法です。
コンポーネントのサイズが動的で、本当にパフォーマンスが必要な場合は、デザインチームに、パフォーマンスを向上させるための再設計を検討できるか尋ねることを検討してください。
keyExtractor または key を使用する
keyExtractor
を FlatList
コンポーネントに設定できます。このプロパティは、キャッシュとアイテムの並べ替えを追跡するための React key
として使用されます。
アイテムコンポーネントで key
プロパティを使用することもできます。
renderItem で匿名関数を避ける
関数型コンポーネントの場合は、renderItem
関数を返された JSX の外に移動します。また、レンダリングごとに再作成されないように、useCallback
フックでラップされていることを確認してください。
クラスコンポーネントの場合は、renderItem
関数を render 関数の外に移動して、render 関数が呼び出されるたびに再作成されないようにします。
const renderItem = useCallback(({item}) => (
<View key={item.key}>
<Text>{item.title}</Text>
</View>
), []);
return (
// ...
<FlatList data={items} renderItem={renderItem} />;
// ...
);