[解決済み] ReactJS: 双方向の無限スクロールのモデル化
質問
私たちのアプリケーションでは、異種アイテムの大きなリストを移動するために無限スクロールを使用しています。いくつかのしわ寄せがあります。
- ユーザーが 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は無限リストを実装する良い方法であることは間違いありません :)
関連
-
[解決済み] スクロールした後に要素が表示されているかどうかを確認するには?
-
[解決済み】ReactJS - "setState "が呼ばれるたびにrenderが呼び出されるのですか?
-
[解決済み】react.jsでレンダリング後にページの先頭にスクロールする。
-
[解決済み】jQueryを使用してページのスクロール位置を検出する方法
-
[解決済み] JSのDateからDay名
-
[解決済み] ExtJS 4のイベントハンドリングについて
-
[解決済み] CORS OriginヘッダーとCSRFトークンによるCSRF保護
-
[解決済み] JavaScriptで文字列を数値に変換する最速の方法は何ですか?
-
[解決済み] <ng-content>が空かどうかを確認する方法は?(これまでのAngular 2+で)
-
[解決済み] JavaScriptデータフォーマット/プリティプリンタ
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] 文字列のn番目の出現箇所を取得するには?
-
[解決済み] URL/アドレスバーからJavascriptの関数を呼び出す
-
[解決済み] javascript の関数から `undefined` と `null` のどちらを返すのが良いのでしょうか?
-
[解決済み] moment.jsでミュータビリティを回避するには?
-
[解決済み] AJAX Mailchimp サインアップフォームの統合
-
[解決済み] jQueryで入力ファイルが空かどうかをチェックする方法
-
[解決済み] モデルフェッチ時に1をtrueに、0をfalseに変換する方法
-
[解決済み] JavaScriptとLuaの微妙な違い [終了しました]
-
[解決済み] HTML要素にスクロールバーがあるかどうかをチェックする
-
[解決済み] Chrome拡張機能:popup.htmlを強制終了させる