ReactJS - 自定義 Hooks:精通無限滾動

Hello, 有志於成為React開發者的你們!今天,我們將踏上一段令人振奮的旅程,探索自定義hooks的世界,特別聚焦於實現無限滾動功能。作為你們友好的鄰居,計算機科學老師,我將一步步引導你們完成這個過程,確保你們掌握每一個概念。所以,拿起你們最喜歡的飲料,放鬆一下,我們一起來深入學習吧!

ReactJS - Custom Hooks

了解自定義 Hooks

在我們深入無限滾動之前,讓我們花一分鐘了解什麼是自定義hooks。在React中,hooks是允許你從函數組件中「hook into」React狀態和生命周期特性的函數。自定義hooks只是使用其他hooks的函數,並可以在組件之間共享。

把自定義hooks想像成你在React開發中的個人瑞士軍刀。它們幫助你將組件邏輯提取到可重用的函數中,使你的代碼更乾淨、更模塊化。

實現無限滾動功能

現在,讓我們來處理我們節目的明星:無限滾動。你可能已在社交媒體平台或新聞網站上遇到過這個功能,當你向下滾動時,內容會持續加載。這是一種很好的提升用戶體驗的方式,可以無縫地展示更多內容,而不需要分頁。

無限滾動的基本原理

在核心上,無限滾動涉及以下三個主要步驟:

  1. 檢測用戶是否已滾動到頁面的底部
  2. 觸發請求以加載更多數據
  3. 將新數據添加到現有內容中

讓我們將這些分解成可管理的部分,並創建我們的自定義hook。

實現 useInfiniteScroll Hook

我們將創建一個名為 useInfiniteScroll 的自定義hook。這個hook將處理當加載更多內容時的邏輯,並為我們提供在組件中實現無限滾動所需的狀態和函數。

以下是我們hook的基本結構:

import { useState, useEffect } from 'react';

const useInfiniteScroll = (callback) => {
const [isFetching, setIsFetching] = useState(false);

useEffect(() => {
window.addEventListener('scroll', handleScroll);
return () => window.removeEventListener('scroll', handleScroll);
}, []);

useEffect(() => {
if (!isFetching) return;
callback();
}, [isFetching]);

function handleScroll() {
if (window.innerHeight + document.documentElement.scrollTop !== document.documentElement.offsetHeight || isFetching) return;
setIsFetching(true);
}

return [isFetching, setIsFetching];
};

export default useInfiniteScroll;

讓我們一步步來分析:

  1. 我們從React中導入 useStateuseEffect。這是我們自定義hook的基石。

  2. 我們的 useInfiniteScroll hook 接受一個 callback 函數作為參數。這將是被觸發以加載更多數據的函數。

  3. 我們使用 useState 創建一個狀態變量 isFetching。這將跟蹤我們是否正在加載更多數據。

  4. 第一個 useEffect 在組件掛載時添加一個滾動事件監聽器,並在組件卸載時移除它。這是我們的清理操作,以防止內存泄漏。

  5. 第二個 useEffect 監聽 isFetching 的變化。當它變為true時,它調用我們的callback函數來加載更多數據。

  6. handleScroll 函數是魔術發生的地方。它檢查我們是否已經滾動到頁面的底部,並且我們不是正在加載數據。如果兩個條件都滿足,它將設置 isFetching 為true。

  7. 最後,我們返回 isFetchingsetIsFetching,這樣使用這個hook的組件可以訪問和更新這個狀態。

現在,讓我們看看我們如何在組件中使用這個hook:

import React, { useState } from 'react';
import useInfiniteScroll from './useInfiniteScroll';

const InfiniteScrollComponent = () => {
const [items, setItems] = useState([]);
const [isFetching, setIsFetching] = useInfiniteScroll(fetchMoreListItems);

function fetchMoreListItems() {
// 模擬API調用
setTimeout(() => {
setItems(prevItems => ([...prevItems, ...Array(20).fill(0).map((_, i) => ({ id: prevItems.length + i, name: `Item ${prevItems.length + i + 1}` }))]));
setIsFetching(false);
}, 2000);
}

return (
<div>
<ul>
{items.map(item => <li key={item.id}>{item.name}</li>)}
</ul>
{isFetching && '正在加載更多列表項目...'}
</div>
);
};

export default InfiniteScrollComponent;

在這個組件中:

  1. 我們使用我們的 useInfiniteScroll hook,傳遞 fetchMoreListItems 函數。
  2. fetchMoreListItems 模擬一個API調用,在2秒後添加20個新項目到我們的列表中。
  3. 我們渲染我們的列表項目,並在 isFetching 為true時顯示一個加載消息。

就这样!一個完全功能的無限滾動實現,使用自定義的React hook。

記住,自定義hooks的美妙之處在於它們的可重用性。現在你可以將這個 useInfiniteScroll hook 在任何需要無限滾動功能的組件中使用。

結論

自定義hooks是React中的一個強大特性,它們讓我們能夠創建可重用的邏輯。通過將無限滾動實現為自定義hook,我們創造了一個靈活、可重用的解決方案,可以輕鬆地集成到各種組件中。

在你繼續你的React之旅時,請繼續探索和創建自定義hooks。它們是保持代碼DRY(Don't Repeat Yourself)和維護乾淨、模塊化代碼庫的絕佳方式。

快樂編程,願你的滾動永遠無限!??

方法 描述
useInfiniteScroll(callback) 實現無限滾動的自定義hook
useState(initialState) 在函數組件中添加狀態的React hook
useEffect(effect, dependencies) 在函數組件中執行副作用操作的React hook
addEventListener(event, handler) 綁定事件處理器到元素的Web API
removeEventListener(event, handler) 從元素中移除事件處理器的Web API
setTimeout(callback, delay) 在指定延遲後執行函數的Web API

Credits: Image by storyset