小さなIntersectionObserverフックでReactの無限スクロールをパッケージなしで実装し、仮想化で長いフィードも高速に保ちます。動くデモとコピーできるコード付き。
最後の項目の後ろに空の番兵要素を置き、IntersectionObserverで監視します。番兵がビューポートから数百ピクセル以内に近づいたら、次のページを取得して末尾に追加します。ライブラリがなくても、20行ほどのフックでこれを実現できます。リストが数千行に達したら仮想化を加え、見えている行だけがDOMに存在するようにしましょう。
無限スクロールで重要なIntersectionObserverのオプション
下の2つのデモはこのページ上で実際に動作します。1つ目はパネルをスクロールすると架空の結果ページを読み込み、2つ目は1万行をスクロールしながら、見えている20行ほどだけを描画します。それぞれのコードはすぐ下にあり、そのままコピーできます。
いいえ。IntersectionObserverは2019年からすべての主要ブラウザーで使え、小さなフックで一般的なケースはまかなえます。リクエストのキャッシュ用にデータ取得ライブラリをすでに使っているなら、組み込みのページング機能を使う価値があります。
仮想化とは、表示領域内の行と少しのバッファだけを、リスト全体の高さを持つスペーサーの中に配置して描画する手法です。DOMに数千行があり、スクロールや入力がもたつき始めたら導入しましょう。@tanstack/react-virtualとそのuseVirtualizerフックがよく使われます。
検索クローラーは人のようにスクロールしないため、スクロール後にしか現れないコンテンツは見つけてもらえない可能性があります。?page=2 のように単独で読み込める実際のページ分割URLでフィードを裏付け、そこへリンクしましょう。
多くの場合、コールバックの参照が変わるせいでエフェクトが毎回の描画でオブザーバーを作り直しているか、最初のページが短すぎて番兵が画面外に押し出されないことが原因です。最新のコールバックはrefに保持し、各ページがビューポートより多くの高さを埋めるようにしましょう。
番兵用のrefを返します。最新のonLoadMoreはrefに保持されるため、オブザーバーは毎回の描画ではなく、enabledが変わるたびに1回だけ作られます。
loadingフラグで二重リクエストを防ぎ、hasMoreで最後にオブザーバーを止めます。
npm install @tanstack/react-virtual でインストールします。外側のボックスがスクロールし、内側のボックスはリスト全体と同じ高さを持ち、見えている各行はtranslateYで所定の位置に移動します。
表示領域付近の行だけが描画されます。estimateSizeは行の高さ(ピクセル)です。
デモ:スクロールに合わせて読み込むフィード
パネル内をスクロールしてください。番兵が範囲に入るたびに10項目の新しいページが届き、最大8ページまで読み込みます。
フィードのデモ
投稿 {n}
読み込み中...
最後まで表示しました。
さらに読み込む
{items}件、{page} / {last}ページ
リセット
デモ:10,000行のうち見えている行だけを描画
リストをスクロールして、ページ上に実際に存在する行がどれほど少ないかを確かめてください。
仮想リストのデモ
行 {n}
{total}行中{shown}行を描画中
無料で始める · クレジットカード不要