1. ホーム
  2. javascript

[解決済み] ReactJS: 双方向の無限スクロールのモデル化

2022-09-08 01:08:01

質問

私たちのアプリケーションでは、異種アイテムの大きなリストを移動するために無限スクロールを使用しています。いくつかのしわ寄せがあります。

  • ユーザーが 10,000 項目のリストを持っていて、3k 以上をスクロールする必要があるのはよくあることです。
  • これらはリッチ アイテムなので、ブラウザのパフォーマンスが許容できなくなる前に、DOM 内に数百のアイテムしか持つことができません。
  • アイテムはさまざまな高さです。
  • アイテムには画像が含まれることがあり、ユーザーが特定の日付にジャンプできるようにしています。これは、ユーザーがリストのポイントにジャンプして、ビューポートより上に画像をロードする必要があり、ロード時にコンテンツが下に押し出される可能性があるため、トリッキーです。この処理に失敗すると、ユーザーがある日付にジャンプしても、それ以前の日付に移動される可能性があります。

既知の不完全なソリューションです。

  • ( リアクトフィニットスクロール ) - これは単純な "底をついたらもっと読み込む" コンポーネントです。これは DOM をカリングしないので、何千ものアイテムで死んでしまいます。

  • ( Reactによるスクロール位置 ) - 最上部に挿入する際にスクロール位置を保存・復元する方法を示します。 または を一番下に挿入しますが、両方を一緒に挿入することはできません。

私は完全なソリューションのコードを探しているわけではありません(それは素晴らしいことですが)。その代わりに、私はこの状況をモデル化する"React方法"を探しています。スクロール位置は状態なのか、そうでないのか?リスト内の位置を保持するために、どのような状態を追跡する必要がありますか? レンダリングされるものの下または上にスクロールするときに新しいレンダリングをトリガーするために、どのような状態を維持する必要がありますか?

どのように解決するのですか?

これは、無限テーブルと無限スクロールのシナリオを混ぜたものです。私が見つけたこのための最良の抽象化は次のとおりです。

概要

を作る。 <List> コンポーネントを作成します。 すべて の子要素の配列を受け取ります。それらをレンダリングしないので、単にそれらを割り当てて捨てるのは本当に安上がりです。10k個のアロケーションが大きすぎるなら、代わりに範囲を受け取って要素を返す関数を渡せばいいのです。

<List>
  {thousandelements.map(function() { return <Element /> })}
</List>

あなたの List コンポーネントは、スクロール位置を追跡し、表示されている子項目のみをレンダリングします。レンダリングされない前の項目をごまかすために、最初に大きな空の div を追加しています。

さて、興味深いのは、一度 Element コンポーネントがレンダリングされると、その高さを測定し、それを List . これにより、スペーサーの高さを計算し、ビューに表示されるべき要素の数を知ることができます。

画像

画像が読み込まれるときに、すべてを下にジャンプさせるということですね。この解決策は、imgタグで画像の寸法を設定することです。 <img src="..." width="100" height="58" /> . こうすれば、ブラウザは、表示されるサイズを知る前にダウンロードするのを待つ必要がなくなります。これには多少のインフラストラクチャが必要ですが、本当に価値のあることです。

サイズを事前に知ることができない場合、画面に onload リスナーを追加し、画像を読み込んだらその表示寸法を測定して、保存されている行の高さを更新し、スクロール位置を補正します。

ランダムな要素でジャンプする

リスト内のランダムな要素にジャンプする必要がある場合、その間の要素のサイズがわからないため、スクロール位置に関するいくつかのトリックが必要になるでしょう。私が提案するのは、すでに計算されている要素の高さを平均し、最後の既知の高さ + (要素数 * 平均) のスクロール位置にジャンプすることです。

これは正確ではないので、最後に知られていた良い位置に戻るときに問題が発生します。競合が発生した場合は、スクロール位置を変更するだけで解決します。これにより、スクロール バーが少し動きますが、あまり影響しないはずです。

Reactの仕様

あなたは キー をレンダリングされたすべての要素に与え、レンダリングをまたいでそれらを維持できるようにしたい。2 つの方法があります。(1) n 個のキー (0, 1, 2, ... n) しか持たない。ここで n は表示できる要素の最大数で、n の倍数の位置を使用する。すべての要素が似たような構造を共有している場合は、(1)を使ってそのDOMノードを再利用するとよいでしょう。そうでない場合は、(2)を使用します。

Reactの状態としては、最初の要素のインデックスと、表示されている要素の数の2つだけですね。現在のスクロール位置とすべての要素の高さは、直接 this . を使用する場合 setState を使う場合、実際には範囲が変更されたときだけ起こるはずの再レンダリングを行なっています。

ここでは の例です。 この回答で説明したテクニックのいくつかを使用した無限リストのです。いくつかの作業が必要ですが、Reactは無限リストを実装する良い方法であることは間違いありません :)