行動すれば次の現実

テック中心の個人ブログ

react-virtualizedのMultiGridでアプリ開発したときのTIPS

f:id:furu07yu:20220415135534p:plain

react-virtualizedとは

SPAで構築されたReactアプリでも、大量のリストを画面いっぱいに表示しようとすると初期描画に時間がかかってしまいます。

これは、画面に見えてない部分も含めて全てのデータをレンダリングしてしまっていることが原因です。

react-virtualizedを使用することで画面に見えている部分のみレンダリングされることができます。

画面をスクロールしたときに、表示されている領域のみのデータが描画される仕様になっていますので、効率的なレンダリングが実現できます。

github.com

react-virtualizedで使用できる様々なコンポーネント

react-virtualizedにはいくつかのコンポーネントが用意されています。簡単に代表的なコンポーネントを紹介します。

  • Grid: エクセルのようにデータを表示することができるコンポーネントです。行と列の固定はできません。
  • MultiGrid: エクセルのようにデータを表示することができるコンポーネントです。行と列の固定が可能です。
  • List: SNSのタイムラインのようにリスト形式でデータを表示することができるコンポーネントです。
  • Table: Listにヘッダーが付いた形式で表示することができるコンポーネントです。
  • Collection: いろいろな大きさのカードを横と縦に配置できるコンポーネントです。

今回は私がよく使用するMultiGridコンポーネントについての知見を共有したいと思います。 MultiGridを使用すると下記のようなエクセルライクな画面が実装できます。

f:id:furu07yu:20220414185459g:plain

基本的な実装方法は公式リファレンスに記載されております。

しかし、あくまでもシンプルな構成を想定している内容になっています。実際にアプリ開発していくと結構なクセがありましたので、その辺りの知見を中心にいくつかピックアップしています。

※react-virtualized v9.22.3に準拠しています

カラムの横幅を動的に変更させたい

カラムの横幅を動的に変更させたい場合、columnWidthというプロパティで制御できます。 columnWidthには引数でindexが渡ってきますので、それを使って横幅を変えることが可能です。

<MultiGrid
  columnWidth={({ index }) => {
    if(index === 0) {
      return 50;
    }
    // index によって返却値の出し分けが可能
    return 100;
  }}
/>

カラムの高さを動的に変更させたい

カラムの高さを動的に変更させたい場合、rowHeightというプロパティで制御できます。 rowHeightには引数でindexが渡ってきますので、それを使って高さを変えることが可能です。

<MultiGrid
  rowHeight={({ index }) => {
    if(index === 0) {
      return 20;
    }
    // index によって返却値の出し分けが可能
    return 40;
  }}
/>

React Hooksでreact-virtualizedを使いたい

リファレンスはクラスベースで記載されておりますが、もちろんHooksでも使用できます。

注意点としてはrecomputeGridSize等のPublic Methodが使用できるようにuseRefでGrid要素への参照ができるように設定することです。

function Grids(props) {

  const gridsEl = useRef(null);

  useLayoutEffect(() => {
    // gridsEl経由でrecomputeGridSizeを実行する
    if (gridsEl) {
      gridsEl.current.recomputeGridSize();
    }
  }, [
    anyProps
  ])

  return (
    <MultiGrid
      // gridsElをrefに設定する
      ref={gridsEl}
    />
  )

セルを結合させたい

MultiGridでセル結合ができれば素晴らしいのですが、この記事を執筆時点(v9.22.3)では残念ながらサポートされていません。

have some cell merge properties? · Issue #1637 · bvaughn/react-virtualized · GitHub

しかし、セル結合されているかのように実装することは可能です。

例えば固定ヘッダーの中で特定のセルを列結合させたい場合は一つのcolumnIndex中に、あたかも2つ列が存在しているかのようにデザインすることでそれが実現できます。

f:id:furu07yu:20220414230507j:plain

上記のように各日付のヘッダーとして発注日を列結合したようなグリッドを作りたいとします。 その場合は、一つのcolumnIndexの中にそれぞれの行を実装することで実現できます。

1行目は単純に1つのcolumnIndexの中に発注日のセルを配置します。

2行目はセル結合されているようにしたいので、1つのcolumnIndexの中にtableタグで7列のテーブルを実装するようにします。

このようにすることで、かなり強引ではありますが、あたかもセル結合されているかのように実装することが可能です。

固定列でもスクロールさせたい

固定列でもスクロールさせたい場合、enableFixedColumnScrollにtrueを設定することで固定列でのスクロールを有効にできます。

そのままではスクロールバーが表示されてしまいますので、一緒にhideBottomLeftGridScrollbarもtrueにしておくことをおすすめします。

固定行でもスクロールさせたい

固定行でもスクロールさせたい場合、enableFixedRowScrollにtrueを設定することで固定行でのスクロールを有効にできます。

そのままではスクロールバーが表示されてしまいますので、一緒にhideTopRightGridScrollbarもtrueにしておくことをおすすめします。