[Angular][ライブラリ] VirtualScrollingでパフォーマンス改善
VirtualScrollingとは
VirtualScrollingとはAngular Material CDKの一つで、表示されている部分のみDOMを生成するもので、パフォーマンス向上に貢献します。
通常、何千件とあるアイテムをfor文などで繰り返しレンダリングすると、見える範囲以外のすべてのDOMを一気に生成するためレスポンスが悪くなります。
そこで、このVirtualScrollingを使うことでレンダリングパフォーマンスを向上させることができます。
導入方法とポイント
Angular CDKをインストールしてあれば、そのままimportすることで使えます。
-
ScrollingModule
のインポートapp.module.ts
import { ScrollingModule } from '@angular/cdk/scrolling'; @NgModule({ declarations: [ AppComponent, VirtualScrollComponent, ], imports: [ BrowserModule, AppRoutingModule, BrowserAnimationsModule, FormsModule, ReactiveFormsModule, ScrollingModule, ], providers: [], bootstrap: [AppComponent] }) export class AppModule { }
-
<cdk-virtual-scroll-viewport>
でスクロール対象を囲う。 -
ngFor
の代わりにcdkVirtualFor
を使う。これはngForと全く同じAPIをサポートします。
実践
virtual-scroll.component.html
<!-- itemSizeとcdkVirtualForのheightは同じにする必要があります。 -->
<cdk-virtual-scroll-viewport itemSize="20" class="virtualScroll-viewport">
<ng-container
*cdkVirtualFor="let item of items" class="virtualScroll-item"
>
<div>
{{item}}
</div>
</ng-container>
</cdk-virtual-scroll-viewport>
virtual-scroll.component.css
.virtualScroll-viewport {
height: 200px;
width: 200px;
border: 1px solid black;
}
.virtualScroll-item {
height: 20px;
}
-
<cdk-virtual-scroll-viewport>
のitemSize
属性と、cdkVirtualFor
のheight
は同じにします。
virtual-scroll.component.ts
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-virtual-scroll',
templateUrl: './virtual-scroll.component.html',
styleUrls: ['./virtual-scroll.component.css']
})
export class VirtualScrollComponent implements OnInit {
items = Array.from({length: 100000}).map((_, i) => `Item #${i}`);
constructor() { }
ngOnInit(): void {
}
}
これで、見えている範囲のDOMだけを生成して読み込んでいることが分かります。
非常に多くのデータを扱う場合はこのようにVvirtualScrollやページネーションの検討が必要です。
appendOnlyモードでレンダリングされたDOMを残す
上記のように実装すると、一度読み込んだDOMがビューから外れる(スクロールして見えなくなる)と、そのDOMは削除されます。これを削除せずに生成したDOMを残すことを保証するにはappendOnly
を使います。
src\app\AngularMaterial\virtual-scroll\virtual-scroll.component.html
<!-- itemSizeとcdkVirtualForのheightは同じにする必要があります。 -->
<cdk-virtual-scroll-viewport appendOnly itemSize="20" class="example-viewport">
<ng-container
*cdkVirtualFor="let item of items" class="example-item"
>
<div>
{{item}}
</div>
</ng-container>
</cdk-virtual-scroll-viewport>
※ 私の環境ではDOMは確かに残り続けるが、しばらくスクロールするとレンダリングされなくなるバグがあり、上手いこと動きませんでした。
参考
Discussion