首頁 > web前端 > js教程 > Reactjs 教學:使用 Intersection Observer 進行無限滾動。

Reactjs 教學:使用 Intersection Observer 進行無限滾動。

Patricia Arquette
發布: 2024-12-17 19:45:11
原創
174 人瀏覽過

什麼是無限滾動以及它的必要性?

滾動是水平或垂直移動網頁上部分內容的使用者操作(在大多數情況下)。

就像您在閱讀本文時所做的那樣。

無限意味著當您向下捲動網頁時,新內容會自動載入。

好吧,但是為什麼每個人都應該實現它?

可發現性

讓我們想像一下您最喜歡的電子商務商店正在舉辦黑色星期五促銷活動。

您在探索頁面上找到了幾個產品,但當您滾動到網頁底部而不是更多產品時,您發現了一個按鈕,可將您帶到下一個產品列表。

您將能夠看到新產品(但前提是您注意到該操作按鈕)。

無限滾動只是幫助用戶找到更多他們可能錯過的內容。

執行

為了實現無限滾動,我們需要檢查使用者是否到達頁面底部或容器。

但是偵測滾動的位置是非常昂貴的,並且由於不同的瀏覽器和設備,其位置值不可靠。

所以一個方法是觀看頁面的最後內容(元素)及其與視窗或容器的交點

我們如何找到交點?

路口觀察者

它是一個 Web API,允許觀察內容或清單末尾的元素

當這個元素(「哨兵」)變得可見(與視窗相交時,它會觸發回調函數

透過這個函數我們可以取得更多資料並將其載入到網頁中。

整個觀察是異步發生的,這最小化對主執行緒的影響。


為了在 Reactjs 中實作 Intersection Observer,我們將以社群動態為例,我們將在貼文清單上進行無限滾動。

看一下這個組件,您就可以了解下面每個部分的詳細情況。

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

登入後複製
登入後複製

cardRefs 一個數組,用來追蹤表示清單中卡片的 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 鍵。

c.觀察最後一個貼文(項目)。
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 接受回呼函數和先前定義的選項物件。

每當觀察到的元素滿足選項中指定的條件時,回呼就會運作。

entries 參數是觀察到的元素的陣列。每個條目都包含有關元素是否相交(可見)的資訊。

如果entry.isIntersecting為true,則表示最後一張卡片現在可見:

  1. 使用 setListItems 將新項目加入清單。
  2. 取消觀察目前元素(entry.target)以防止冗餘觸發器。

觀察最後一張牌

 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 所建立的所有觀察者。

這確保了當元件卸載或重新渲染時,舊的觀察者被清理。


Reactjs Tutorial : Infinite scrolling with Intersection Observer.

每個階段會發生什麼事?

1。使用者滾動

當使用者捲動時,最後一張卡片進入視圖

2。路口觀察者觸發器

當最後一張牌的50%可見時,觀察者的回檔
運行。

3。新增項目

回呼將新項目加入到清單中 (setListItems)。

4。重複

觀察者與舊的最後一張卡片斷開連接並附加到
新的最後一張卡。

Reactjs Tutorial : Infinite scrolling with Intersection Observer.

這就是我們如何使用 Intersection Observer.

實現無限滾動

希望這對您有幫助:)

謝謝。

以上是Reactjs 教學:使用 Intersection Observer 進行無限滾動。的詳細內容。更多資訊請關注PHP中文網其他相關文章!

來源:dev.to
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
作者最新文章
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板