メインコンテンツにスキップ

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 を使用する

keyExtractorFlatList コンポーネントに設定できます。このプロパティは、キャッシュとアイテムの並べ替えを追跡するための 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} />;
// ...
);