【LWC】datatableで無限スクロールを実装する

#はじめに
前回はdatatableにおける大量データ時の表示方法としてページングを実装しました。今回は無限スクロールを実装してみました。
無限スクロールは縦長のサイトで使用されていて下にスクロールするごとに新たにページを読み込んでデータを表示する方法です。
Salesforceであればリストビューに使用されていますね。詳しい説明については各種サイトをご覧ください。

#動作
初期として20件表示
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407598/a4ed4098-a1da-92f9-b468-fe8a0fd6380c.png)
↓↓　下にスクロール

50件まで表示
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407598/247f9852-a773-ee55-f515-16c85db934e7.png)

本当は動画のほうが分かりやすいですが今回は画像でご容赦ください。（動きとしてはリストビューと同じなのでそちらをご確認ください。）


#datatableの作成
```html:dataTableWithScroll.html
<template>
    <lightning-card title="取引先責任者" icon-name="custom:custom1">
      <div class="slds-box" style="height:400px;">
        <template if:true={contacts}>
          <lightning-datatable
            key-field="Id"
            data={contacts}
            columns={columns}
            hide-checkbox-column
            enable-infinite-loading
            onloadmore={loadMoreData}>
          </lightning-datatable>
        </template>
      </div>
      ステータス：{loadMoreStatus}
    </lightning-card>
</template>
```
LWC標準のdatatableを作成します。
無限スクロールのために、「ebable-infinite-loading」とonloadmore属性でスクロールした時の挙動を定義します。

#Limitとoffsetでレコードを順番に取得
```javascript:dataTableWithScroll.js
import { LightningElement, api, wire, track } from 'lwc';
import getContactsWithOffSet from '@salesforce/apex/ContactHandler.getContactsWithOffSet';

const columns = [
  { label: '氏名', fieldName: 'Name', type: 'url', typeAttributes: {label: {fieldName: 'Name'}, tooltip: {fieldName: 'Name'}}},
  { label: '電話', fieldName: 'Phone'},
  { label: '役職', fieldName: 'Title'},
]

export default class DataTableWithScroll extends LightningElement {
  @api recordId;
  @track contacts = [];
  rowLimit = 20;
  rowOffSet = 0;
  loadMoreStatus;
  limitRows = 50;
  targetDatatable;
  columns = columns;

  connectedCallback() {
    this.loadData();
  }

  loadData() {
    getContactsWithOffSet({accId: this.recordId, limitSize: this.rowLimit, offset: this.rowOffSet})
    .then(result => {
      let tempContactList = [];
      for(let i = 0; i < result.length; i++) {
        let tempRecord = Object.assign({}, result[i]);
        tempRecord.recordLink = '/lightning/r/' + tempRecord.Id + '/view';
        tempContactList.push(tempRecord);
      }
      let updateRecords = [...this.contacts, ...tempContactList];
      this.contacts = updateRecords;
      this.loadMoreStatus = '';
      console.log('サイズ：' + this.contacts.length);
      if(this.contacts.length >= this.limitRows) {
        console.log('スクロール終了');
        this.targetDatatable.enableInfiniteLoading = false;
        this.loadMoreStatus = 'これ以上データはありません';
      }
      if(this.targetDatatable) {
        this.targetDatatable.isLoading = false;
      }
    })
    .catch(error => {
      console.log('エラー：' + error);
    });
  }

  loadMoreData(event) {
    event.preventDefault();
    event.target.isLoading = true;
    this.targetDatatable = event.target;
    this.loadMoreStatus = 'Loading';

    this.rowOffSet = this.rowOffSet + this.rowLimit;
    this.loadData();

  }
}
```
ApexクラスでLimitとOffsetを使用して20件づつレコードを取得します。今回はレコードを最大50件に制限しています。50件超えてスクロールした場合に永遠と空レコードをロードしたくないので、if分岐してenableInfiniteLoadingをfalseにしています。
「this.targetDatatable.enableInfiniteLoading = false」のような形でdatatableの属性操作できるの知りませんでした。

一応Apexクラスのほうも載せておきます。

```apex:ContactHandler.cls
public with sharing class ContactHandler {
    public ContactHandler() {

    }

    @AuraEnabled(cacheable=true)
    public static List<Contact> getContactsWithOffSet(Id accId, Integer limitSize, Integer offset){
        return [SELECT Id, Name, Phone, Title, Email FROM CONTACT WHERE AccountId = :accId LIMIT :limitSize OFFSET :offset];
    }
}
```

#ページネーションと比べて
ページネーションと無限スクロールの比較ですが、実装の難易度はどちらも変わらない気がします。パフォーマンスで言うとページングはデータの取得が1度だけなので無限スクロールに比べてよいです。あとはUIですが、無限スクロールの場合1ページに何件も表示することが出来ますが、レコードが増えすぎるとページが縦長になりすぎます。ページネーションはページ数が明記されることが多く、レコードの件数が分かることがメリットですが、余分なクリック動作が必要なところがデメリットな気がします。
Salesforceのレコードを条件を絞って表示する場合、100件以上表示することは少ないと思うので無限スクロールのほうがUI的には良いのかなと思います。

#今後の課題
今50件の制限をかけてその数に達した場合に無限スクロールが出来ないように制御していますが、レコードがそもそも50件より少ない場合は永遠にロードするようになってしまいます。また時間があればその部分を修正したいと思います。