Angular CDK を使用して大規模なリストを仮想化する

仮想スクロールを実装して、大きなリストの応答性を高めます。

Stephen Fluin
Stephen Fluin

スクロール リストは、お気に入りのソーシャル メディア サイトで無限スクロールのフィードを閲覧する場合でも、企業向けダッシュボードを操作する場合でも、今日最も一般的な UI パターンの一つです。スクロール リストが非常に長い場合(数百、数千、数十万のアイテムなど)、アプリのパフォーマンスが低下する可能性があります。

リストが大きい場合、アプリケーションはすべてのデータを事前に読み込んでレンダリングする必要があるため、読み込みに時間がかかることがあります。また、リスト内の各アイテムに豊富なデータ、メディア、機能が含まれているため、レンダリングとナビゲーションが遅くなることもあります。

ページの読み込みやスクロール時に問題が発生し、ユーザーの不満を招いてページから離脱する可能性があります。

このようなスケーリングの問題に対処するために使用される主な手法は、仮想スクロールです。仮想スクロールでは、適切なサイズのスクロールバーを表示することで、非常に大きなリストのように見せることができます。また、リスト全体をメモリに保持したり、ページにレンダリングしたりすることなく、リストを操作できます。

Angular では、仮想スクロールは Component Dev Kit(CDK)によって提供されます。リストの反復処理方法を変更し、いくつかの追加の構成パラメータを指定すると、CDK の仮想スクロールによってリストの仮想レンダリングが自動的に管理され、ページのパフォーマンスと応答性が向上します。

リスト全体を一度にレンダリングするのではなく、画面に収まるアイテムのサブセット(および小さなバッファ)のみがレンダリングされます。ユーザーが移動すると、アイテムの新しいサブセットが計算され、レンダリングされます。必要に応じて、既存の DOM が再利用されます。

この投稿の残りの部分では、基本的な仮想スクロールを設定する方法について説明します。動作する完全なサンプルは、こちらのサンプルアプリで確認できます。

仮想スクロールを設定する

まず、任意のパッケージ マネージャーを使用して @angular/cdk がインストールされていることを確認します。npm を使用してインストールするには、ターミナルで次のコマンドを実行します。

npm install --save @angular/cdk

ScrollingModule をアプリに追加します。

CDK がインストールされている状態で、仮想スクロールを処理する ScrollingModule@angular/cdk/scrolling パッケージからインポートします。次に、モジュールのインポート アレイに追加します。

import {ScrollingModule} from '@angular/cdk/scrolling';

...
imports
: [
 
ScrollingModule
...
]
...

ビューポートを作成する

このパッケージの仕組みを確認するには、0 ~ 99,999 の単純な数値リストを含むコンポーネントを作成します。

@Component({
  template
: `<div *ngFor="let item of list">{{item}}</div>`
})
export class ScrollComponent {
  list
= Array.from({length: 100000}).map((_, i) => i);
}

ブラウザがアプリをレンダリングする際に、10 万個の個々の <div> 要素をレンダリングする必要があります。これは単純なテキストノードには問題ありませんが、繰り返しテンプレートの複雑さはスケーリングに適しておらず、イベント リスナーは大幅に増加します。

仮想スクロールを追加してこれらの問題を回避するには、リストを <cdk-virtual-scroll-viewport> 要素でラップしてビューポートを作成する必要があります。

@Component({
 
template: `<cdk-virtual-scroll-viewport>
    <div *ngFor="let item of list">{{item}}</div>
    </cdk-virtual-scroll-viewport>`

})
export class ScrollComponent {
  list
= Array.from({length: 100000}).map((_, i) => i);
}

ScrollingModule はリストのサブセットを動的にレンダリングするため、標準の CSS を使用してビューポートの高さを指定する必要があります。また、itemSize を指定して、ビューポートにコンテンツに関するヒントを提供する必要があります。このモジュールは、この情報を使用して、特定の時点で DOM に保持するアイテムの数と、適切なサイズのスクロールバーをレンダリングする方法を決定します。

@Component({
 
template: `<cdk-virtual-scroll-viewport itemSize="18" style="height:80vh">
    <div *ngFor="let item of list">{{item}}</div>
    </cdk-virtual-scroll-viewport>`

})
export class ScrollComponent {
  list
= Array.from({length: 100000}).map((_, i) => i);
}

最後に、*ngFor*cdkVirtualFor に変換します。

@Component({
  template
: `<cdk-virtual-scroll-viewport itemSize="18" style="height:80vh">
   
<div *cdkVirtualFor="let item of list">{{item}}</div>
   
</cdk-virtual-scroll-viewport>`
})
export class ScrollComponent {
  list
= Array.from({length: 100000}).map((_, i) => i);
}

ビューポートは、リスト全体を反復処理するのではなく、ユーザーに適したリストのサブセットを動的に特定して反復処理します。これで、ユーザーがページを読み込むと、CDK は画面に収まるリストのサブセット(および少しのバッファ)をレンダリングします。ビューポート内のスクロール イベントが発生すると、リストの適切なサブセットが読み込まれ、レンダリングされます。

ユーザーがスクロールすると、CDK がリストのサブセットをレンダリングします。

詳細

CDK の仮想スクロール機能は、この基本的な例よりもはるかに高度です。サンプルアプリでは、リスト全体がメモリに格納されていましたが、より複雑なアプリケーションでは、リストをオンデマンドで取得できます。ScrollingModulecdkVirtualOf ディレクティブのその他の機能については、CDK のドキュメントScrolling をご覧ください。

ヒーロー画像: Mr Cup / Fabien Barral、Unsplash より。