React Nativeでのより良いリストビュー
多くの方が、コミュニティグループでのティザー発表の後、すでに新しいリストコンポーネントの一部を使い始めていると思いますが、本日、正式に発表します!ListView
やDataSource
、古い行、無視されたバグ、過剰なメモリ消費はもうありません。最新のReact Native 2017年3月リリース候補版(0.43-rc.1
)では、新しいコンポーネントスイートの中から、あなたのユースケースに最適なものを選択でき、優れたパフォーマンスと機能セットがすぐに利用できます。
<FlatList>
これはシンプルでパフォーマンスの高いリストのための主力コンポーネントです。データの配列とrenderItem
関数を指定すれば、すぐに利用できます。
<FlatList
data={[{title: 'Title Text', key: 'item1'}, ...]}
renderItem={({item}) => <ListItem title={item.title} />}
/>
<SectionList>
データセットを論理的なセクションに分割して表示したい場合、セクションヘッダー(例:アルファベット順のアドレス帳)を付けたり、異種データとレンダリング(例:ボタンがいくつかあるプロフィールビューの後にコンポーザー、次にフォトグリッド、次にフレンドグリッド、最後にストーリーのリストが続くなど)を伴う可能性がある場合、これが最適な方法です。
<SectionList
renderItem={({item}) => <ListItem title={item.title} />}
renderSectionHeader={({section}) => <H1 title={section.key} />}
sections={[ // homogeneous rendering between sections
{data: [...], key: ...},
{data: [...], key: ...},
{data: [...], key: ...},
]}
/>
<SectionList
sections={[ // heterogeneous rendering between sections
{data: [...], key: ..., renderItem: ...},
{data: [...], key: ..., renderItem: ...},
{data: [...], key: ..., renderItem: ...},
]}
/>
<VirtualizedList>
より柔軟なAPIを備えた舞台裏の実装です。データが単純な配列ではない場合(イミュータブルなリストなど)に特に便利です。
機能
リストは多くの文脈で使用されるため、新しいコンポーネントには、ほとんどのユースケースをすぐに処理できる機能が満載されています。
- スクロールによる読み込み(
onEndReached
)。 - Pull to refresh(
onRefresh
/refreshing
)。 - 設定可能な可視性 (VPV) コールバック (
onViewableItemsChanged
/viewabilityConfig
)。 - 水平モード(
horizontal
)。 - インテリジェントなアイテムとセクションのセパレータ。
- 複数カラムのサポート(
numColumns
)。 scrollToEnd
、scrollToIndex
、およびscrollToItem
。- より良いFlowタイピング。
いくつかの注意点
-
コンテンツがレンダーウィンドウの外にスクロールされると、アイテムのサブツリーの内部状態は保持されません。すべてのデータがアイテムデータまたはFlux、Redux、Relayなどの外部ストアにキャプチャされていることを確認してください。
-
これらのコンポーネントは
PureComponent
に基づいているため、props
がシャロー比較で等しいままであれば再レンダリングされません。renderItem
関数が直接依存するすべてのものが、更新後も===
ではないプロップとして渡されていることを確認してください。そうでない場合、UIが変更されても更新されない可能性があります。これには、data
プロップと親コンポーネントの状態が含まれます。例えば、<FlatList
data={this.state.data}
renderItem={({item}) => (
<MyItem
item={item}
onPress={() =>
this.setState(oldState => ({
selected: {
// New instance breaks `===`
...oldState.selected, // copy old data
[item.key]: !oldState.selected[item.key], // toggle
},
}))
}
selected={
!!this.state.selected[item.key] // renderItem depends on state
}
/>
)}
selected={
// Can be any prop that doesn't collide with existing props
this.state.selected // A change to selected should re-render FlatList
}
/> -
メモリを制約し、スムーズなスクロールを可能にするために、コンテンツは画面外で非同期にレンダリングされます。これは、フィルレートよりも速くスクロールすると、一時的に空白のコンテンツが表示される可能性があることを意味します。これは、各アプリケーションのニーズに合わせて調整できるトレードオフであり、舞台裏で改善に取り組んでいます。
-
デフォルトでは、これらの新しいリストは各アイテムの
key
プロップを探し、それをReactのキーとして使用します。代わりに、カスタムのkeyExtractor
プロップを提供することもできます。
パフォーマンス
APIの簡素化に加えて、新しいリストコンポーネントはパフォーマンスが大幅に向上しており、主なものは、行数に関係なくメモリ使用量がほぼ一定であることです。これは、レンダリングウィンドウ外の要素をコンポーネント階層から完全にアンマウントし、ReactコンポーネントからのJSメモリと、シャドウツリーとUIビューからのネイティブメモリを再利用することで「仮想化」することによって行われます。これには、内部コンポーネントの状態が保持されないという注意点があるため、重要な状態は、コンポーネント自体以外の場所(例:Relay、Redux、Fluxストアなど)で追跡するようにしてください。
レンダリングウィンドウを制限することで、Reactやネイティブプラットフォームが行う必要がある作業量も削減されます。たとえば、ビューのトラバーサルなどです。たとえ100万個の要素の最後のものをレンダリングしている場合でも、これらの新しいリストを使用すれば、レンダリングのためにそれらすべての要素を繰り返し処理する必要はありません。scrollToIndex
を使用すれば、過剰なレンダリングなしに真ん中にジャンプすることもできます。
スケジューリングにもいくつかの改善を加え、アプリケーションの応答性を向上させるはずです。レンダリングウィンドウの端にある項目は、アクティブなジェスチャー、アニメーション、その他のインタラクションが完了した後、低頻度で低い優先度でレンダリングされます。
高度な使い方
ListView
とは異なり、レンダリングウィンドウ内のすべての項目は、プロパティが変更されるたびに再レンダリングされます。通常、これはウィンドウ処理によって項目の数が一定に減少するため問題ありませんが、項目が複雑な場合は、Reactのパフォーマンスに関するベストプラクティスに従い、React.PureComponent
および/またはshouldComponentUpdate
をコンポーネント内で適切に使用して、再帰的なサブツリーの再レンダリングを制限するようにしてください。
行の高さがレンダリングせずに計算できる場合は、getItemLayout
プロパティを提供することで、ユーザーエクスペリエンスを向上させることができます。これにより、scrollToIndex
などで特定の項目にスクロールする際に格段にスムーズになり、コンテンツの高さがレンダリングせずに決定できるため、スクロールインジケータUIが改善されます。
イミュータブルなリストのような代替データ型がある場合は、<VirtualizedList>
が最適です。これはgetItem
プロップを受け取り、任意のインデックスのアイテムデータを返すことができ、より緩やかなFlowタイピングを持っています。
また、特殊なユースケースがある場合に調整できるパラメーターも多数あります。たとえば、windowSize
を使用してメモリ使用量とユーザーエクスペリエンスのバランスを取ったり、maxToRenderPerBatch
を使用してフィルレートと応答性のバランスを調整したり、onEndReachedThreshold
を使用してスクロールロードが発生するタイミングを制御したりできます。
今後の作業
- 既存のサーフェスの移行(最終的には
ListView
の非推奨化)。 - 必要性を見聞きするにつれて、より多くの機能を追加(ぜひお知らせください!)。
- スティッキーなセクションヘッダーのサポート。
- さらなるパフォーマンスの最適化。
- 状態を持つ関数型アイテムコンポーネントのサポート。