ホームページ >ウェブフロントエンド >jsチュートリアル >Reactjs チュートリアル : Intersection Observer を使用した無限スクロール。
スクロールは、Web ページ上のコンテンツの一部を (ほとんどの場合) 水平方向または垂直方向に移動するユーザー操作です。
この記事を読んでいるときと同じように。
Infinite とは、Web ページを下にスクロールすると、新しいコンテンツが自動的に読み込まれることを意味します。
まあまあですが、なぜ誰かがそれを実装する必要があるのでしょうか?
発見可能性
お気に入りの e コマース ストアでのブラック フライデー セールを想像してみましょう。
検索ページでいくつかの製品が見つかりましたが、他の製品ではなくウェブページの一番下までスクロールすると、次の製品リストに移動するボタンが見つかりました。
新製品を確認できるようになります (ただし、アクション ボタンに気づいた場合のみ)。
無限スクロール は、ユーザーが他の方法では見逃していた可能性のあるコンテンツをさらに見つけるのに役立ちます。
無限スクロールを実装するには、ユーザーがページまたはコンテナの下部に到達したかどうかをチェックし続ける必要があります。
しかし、スクロールの位置を検出するのは非常にコストがかかり、ブラウザやデバイスが異なるためその位置の値は信頼できません。
その 1 つの方法は、ページの最後のコンテンツ (要素) とビューポートまたはコンテナとの交差点を監視することです。
交点はどのように見つけますか?
これは、コンテンツまたはリストの末尾にある要素を観察できるようにする Web API です。
この 要素 (「センチネル」) が表示されると (ビューポートと交差し、コールバック関数がトリガーされます。
この関数を通じて、より多くのデータを取得し、Web ページに読み込むことができます。
この観察全体は非同期で行われます。これにより、メインスレッドへの影響が最小限に抑えられます。
このコンポーネントを見てください。このコンポーネントのすぐ下にある各部分の内訳をたどることができます。
import { useEffect, useRef, useState } from "react"; interface IIntersectionObserverProps {} const allItems = [ "https://picsum.photos/200", "https://picsum.photos/200", "https://picsum.photos/200", "https://picsum.photos/200", ]; const IntersectionObserverImplement: React.FunctionComponent< IIntersectionObserverProps > = (props) => { const cardRefs = useRef<(HTMLDivElement | null)[]>([]); // Initialize as an empty array const containerRef = useRef<HTMLDivElement | null>(null); const [listItems, setListItems] = useState(allItems); useEffect(() => { const options = { root: containerRef.current, rootMargin: "0px", threshold: 0.5, }; const observer = new IntersectionObserver((entries, observer) => { entries.forEach((entry) => { if (entry.isIntersecting) { setListItems((prevItems) => [ ...prevItems, "https://picsum.photos/200", ]); observer.unobserve(entry.target); // Stop observing the current element } }); }, options); // Observe the last card only const lastCard = cardRefs.current[listItems.length - 1]; if (lastCard) { observer.observe(lastCard); } return () => observer.disconnect(); // Clean up observer on unmount }, [listItems]); return ( <div className="container" ref={containerRef}> {listItems.map((eachItem, index) => ( <div className="card" ref={(el) => (cardRefs.current[index] = el)} // Assign refs correctly key={index} > <h5>Post {index}</h5> <img width={"200"} height={"150"} src={eachItem} /> </div> ))} </div> ); }; export default IntersectionObserverImplement;
目標は、フィード リストの最後の投稿 (センチネルと呼ばれます) がビューポートと交差するタイミングを検出することです。これが発生すると、さらに投稿が読み込まれて表示されます。
const cardRefs = useRef<(HTMLDivElement | null)[]>([]); // For storing references to each card const containerRef = useRef<HTMLDivElement | null>(null); // Reference to the scrollable container const [listItems, setListItems] = useState(allItems); // State to hold the list of itemscardRefs リスト内のカードを表す DOM 要素を追跡する配列。
containerRef スクロール可能なコンテナを参照します。
listItems ページ上に現在表示されている項目の配列を保持します。
b.リストのレンダリングと参照の割り当て
return ( <div className="container" ref={containerRef}> {listItems.map((eachItem, index) => ( <div className="card" ref={(el) => (cardRefs.current[index] = el)} // Assign a ref to each card key={index} > <h5>Post {index}</h5> <img width={"200"} height={"150"} src={eachItem} /> </div> ))} </div> );containerRef スクロールが行われるコンテナをマークします。
cardRefs リスト内の各カードに参照を割り当てます。これにより、どの要素 (最後のカードなど) を監視するかをオブザーバーに確実に伝えることができます。
listItems をマップして、リスト内の各項目をレンダリングします。
各 div はカードとしてスタイル設定され、React 用の一意のキーを持ちます。
import { useEffect, useRef, useState } from "react"; interface IIntersectionObserverProps {} const allItems = [ "https://picsum.photos/200", "https://picsum.photos/200", "https://picsum.photos/200", "https://picsum.photos/200", ]; const IntersectionObserverImplement: React.FunctionComponent< IIntersectionObserverProps > = (props) => { const cardRefs = useRef<(HTMLDivElement | null)[]>([]); // Initialize as an empty array const containerRef = useRef<HTMLDivElement | null>(null); const [listItems, setListItems] = useState(allItems); useEffect(() => { const options = { root: containerRef.current, rootMargin: "0px", threshold: 0.5, }; const observer = new IntersectionObserver((entries, observer) => { entries.forEach((entry) => { if (entry.isIntersecting) { setListItems((prevItems) => [ ...prevItems, "https://picsum.photos/200", ]); observer.unobserve(entry.target); // Stop observing the current element } }); }, options); // Observe the last card only const lastCard = cardRefs.current[listItems.length - 1]; if (lastCard) { observer.observe(lastCard); } return () => observer.disconnect(); // Clean up observer on unmount }, [listItems]); return ( <div className="container" ref={containerRef}> {listItems.map((eachItem, index) => ( <div className="card" ref={(el) => (cardRefs.current[index] = el)} // Assign refs correctly key={index} > <h5>Post {index}</h5> <img width={"200"} height={"150"} src={eachItem} /> </div> ))} </div> ); }; export default IntersectionObserverImplement;
オプション オブジェクト
const cardRefs = useRef<(HTMLDivElement | null)[]>([]); // For storing references to each card const containerRef = useRef<HTMLDivElement | null>(null); // Reference to the scrollable container const [listItems, setListItems] = useState(allItems); // State to hold the list of items
root スクロールコンテナを指定します。
containerRef.current は、すべてのカードをラップする div を参照します。
root が null の場合、デフォルトでビューポートを監視します。
rootMargin: ルートの周囲の余分なマージンを定義します。
「0px」は余分なスペースがないことを意味します。 「100px」のような値を使用すると、オブザーバーをより早くトリガーすることができます (要素が表示されそうになったときなど)。
しきい値: オブザーバーがトリガーするために、ターゲット要素がどの程度表示される必要があるかを決定します。
0.5 は、最後のカードの 50% が表示されたときにコールバックがトリガーされることを意味します。
オブザーバーの作成
return ( <div className="container" ref={containerRef}> {listItems.map((eachItem, index) => ( <div className="card" ref={(el) => (cardRefs.current[index] = el)} // Assign a ref to each card key={index} > <h5>Post {index}</h5> <img width={"200"} height={"150"} src={eachItem} /> </div> ))} </div> );
IntersectionObserver コールバック関数と前に定義したオプション オブジェクトを受け入れます。
コールバックは、監視された要素がオプションで指定された条件を満たすたびに実行されます。
entrys パラメータは、観測された要素の配列です。各エントリには、要素が交差している (表示されている) かどうかに関する情報が含まれています。
entry.isIntersecting が true の場合、最後のカードが表示されていることを意味します。
最後のカードを観察する
useEffect(() => { const options = { root: containerRef.current, rootMargin: "0px", threshold: 0.5, }; const observer = new IntersectionObserver((entries, observer) => { entries.forEach((entry) => { if (entry.isIntersecting) { setListItems((prevItems) => [ ...prevItems, "https://picsum.photos/200", ]); observer.unobserve(entry.target); // Stop observing the current element } }); }, options); // Observe each card const lastCard = cardRefs.current[listItems.length - 1]; if (lastCard) { observer.observe(lastCard); } return () => observer.disconnect(); // Clean up observer on unmount }, [listItems]);
cardRefs.current: すべてのカードへの参照を追跡します。
listItems.length - 1: リスト内の最後の項目を識別します。
lastCard が存在する場合は、observer.observe(lastCard) を使用して監視を開始します。
オブザーバーはこのカードを監視し、カードが表示されるとコールバックをトリガーします。
片付け
const options = { root: containerRef.current, // Observe within the container rootMargin: "0px", // No margin around the root container threshold: 0.5, // Trigger when 50% of the element is visible };
observer.disconnect() は、この useEffect によって作成されたすべてのオブザーバーを削除します。
これにより、コンポーネントがアンマウントまたは再レンダリングされるときに、古いオブザーバーが確実にクリーンアップされます。
各段階では何が起こりますか?
1.ユーザースクロール
ユーザーがスクロールすると、最後のカードが表示されます
2.交差点オブザーバーのトリガー
最後のカードの 50% が表示されると、オブザーバーのコールバック
実行します。
3.アイテムを追加
コールバックは新しい項目をリスト (setListItems) に追加します。
4.繰り返し
オブザーバーは古い最後のカードから切断し、
に接続します
新しい最後のカード。
これが、Intersection Observer を使用して無限スクロールを実装する方法です。
これがお役に立てば幸いです:)
ありがとうございます。
以上がReactjs チュートリアル : Intersection Observer を使用した無限スクロール。の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。