Handsontableのレスポンス改善

Handsontableでセルに入力された値と、元々セルにロードしてある値を元に計算して結果を別のセルに反映するというような処理を書いたのだが、最初に書いたコードではレスポンスが悪すぎて使い物にならなかったので改善したよという話。

そもそもどういうコードを書いたのか

あんまり詳しく書くと守秘義務がアレなのでボカして書きますが、前年度の売り上げと会社の営業日数、それと今年度の営業日数のデータが既にロードされており、そこに今年度の売り上げ目標を入力すると、前年度比(単純に前年度との比較)と実質前年度比(営業日数差を加味した値)が計算されて、さらに上期、下期、年度での数値も計算するという処理を書きました。

最初に書いたコードはgetDataAtCellで入力があった月の各データを取得して計算、結果を対象のセルにsetDataAtCellで書き込むという教科書通りの内容でしたが、上述の通りこれのレスポンスが悪すぎてどうにもなりませんでした。

どうやら個々のセルに対していちいちsetDataAtCellをかけると、グリッドへの値の書き込みとブラウザでのレンダリングを書き込むセルの回数繰り返してしまうためレスポンスが極端に悪くなるようです。

じゃぁどうコードを書けばいいのよ

結論から言うと、getSourceDataでグリッドにロードされているデータのオブジェクトを取得し、そのオブジェクトに計算結果を適用してからloadDataで読み込めばOKです。これならグリッドへの値の書き込みもブラウザにレンダリングさせる回数も1回で済みます。

ただし、loadDataを使うのでセル設定などはロード直後の状態に戻ってしまうので、特定のセルにsetCellMetaなどしている場合は再度同じ設定をかけてあげる必要があります。またグリッドがソートされている場合はisSortedで条件を分岐した上でtoPhysicalRowやtoPhysicalColumnを使って表示されているグリッドのセル座標を実際のデータのセル座標に変換してあげないといけませんので注意してください。

2021/10/20追記

グリッドがソートされているのであれば、きちんとgetSortConfigしてloadDataの後でsetSortConfigするのを忘れないようにね。

あとloadDataだとaddHookOnceでafterLoadDataを指定して、その中でpromiseをresolveするようにすればデータロード完了のタイミングが取れるので便利です。afterSetDataAtCellだと最後のsetDataAtcellだとの判断が必要になるのでちょっと手間かかるからね。