自訂鉤子不僅僅是 React 中的一個便利性——它們也是模組化和可維護程式碼的遊戲規則改變者。它們允許開發人員以以前不可能的方式封裝邏輯、管理狀態並簡化複雜的功能。
React 強大的函數式程式設計範式重新定義了現代前端開發,為模組化、可維護和可重複使用的程式碼鋪平了道路。在其眾多功能中,自訂掛鉤作為建置更智慧、更清潔元件的關鍵推動者脫穎而出。今天,讓我們深入研究每個開發人員工具包中都應該擁有的一些基本自訂鉤子,並學習如何有效地實現它們。
取得資料是 React 中常見的任務。 useFetch 鉤子抽象化了重複的邏輯,簡化了 API 呼叫並優雅地管理狀態。
執行:
import { useState, useEffect } from "react";
function useFetch<T>(url: string) {
const [data, setData] = useState<T | null>(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<Error | null>(null);
useEffect(() => {
const fetchData = async () => {
setLoading(true);
try {
const response = await fetch(url);
const result = await response.json();
setData(result);
} catch (err) {
setError(err as Error);
} finally {
setLoading(false);
}
};
fetchData();
}, [url]);
return { data, loading, error };
}
export default useFetch;
用法:
const { data, loading, error } = useFetch<User[]>('/api/users');
if (loading) return <p>Loading...</p>;
if (error) return <p>Error: {error.message}</p>;
return <ul>{data?.map(user => <li key={user.id}>{user.name}</li>)}</ul>;
透過防手震鉤子可以有效處理頻繁的使用者輸入(例如搜尋或表單欄位),從而減少不必要的渲染和 API 呼叫。
執行:
import { useState, useEffect } from "react";
function useDebounce<T>(value: T, delay: number): T {
const [debouncedValue, setDebouncedValue] = useState(value);
useEffect(() => {
const handler = setTimeout(() => setDebouncedValue(value), delay);
return () => clearTimeout(handler);
}, [value, delay]);
return debouncedValue;
}
export default useDebounce;
用法:
const [searchTerm, setSearchTerm] = useState('');
const debouncedSearch = useDebounce(searchTerm, 500);
useEffect(() => {
if (debouncedSearch) {
// Trigger API or other actions
}
}, [debouncedSearch]);
「使用自訂 useToggle 掛鉤可以輕鬆管理模態、下拉式選單或主題開關的切換狀態,從而保持程式碼整潔且可重複使用。
執行:
import { useState } from "react";
function useToggle(initialState = false) {
const [state, setState] = useState(initialState);
const toggle = () => setState(prev => !prev);
return [state, toggle] as const;
}
export default useToggle;
用法:
const [isModalOpen, toggleModal] = useToggle();
return (
<div>
<button onClick={toggleModal}>Toggle Modal</button>
{isModalOpen && <p>Modal Content</p>}
</div>
);
透過自訂 useLocalStorage 掛鉤,從 localStorage 儲存和擷取資料變得無縫且可重複使用。
執行:
import { useState } from "react";
function useLocalStorage<T>(key: string, initialValue: T) {
const [storedValue, setStoredValue] = useState<T>(() => {
try {
const item = window.localStorage.getItem(key);
return item ? JSON.parse(item) : initialValue;
} catch (error) {
console.error(error);
return initialValue;
}
});
const setValue = (value: T) => {
try {
setStoredValue(value);
window.localStorage.setItem(key, JSON.stringify(value));
} catch (error) {
console.error(error);
}
};
return [storedValue, setValue] as const;
}
export default useLocalStorage;
用法:
const [theme, setTheme] = useLocalStorage('theme', 'light');
return (
<button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>
Toggle Theme
</button>
);
追蹤值的先前狀態對於比較和動畫至關重要,可以透過自訂 usePrevious 掛鉤輕鬆實現。
執行:
import { useEffect, useRef } from "react";
function usePrevious<T>(value: T): T | undefined {
const ref = useRef<T>();
useEffect(() => {
ref.current = value;
}, [value]);
return ref.current;
}
export default usePrevious;
用法:
const [count, setCount] = useState(0);
const prevCount = usePrevious(count);
return (
<p>
Now: {count}, Before: {prevCount}
</p>
);
非常適合在單擊外部時關閉模式或下拉式選單,使用自訂 useClickOutside 掛鉤以獲得更好的使用者體驗。
執行:
import { useEffect, useRef } from "react";
function useClickOutside(handler: () => void) {
const ref = useRef<HTMLDivElement>(null);
useEffect(() => {
const handleClickOutside = (event: MouseEvent) => {
if (ref.current && !ref.current.contains(event.target as Node)) {
handler();
}
};
document.addEventListener('mousedown', handleClickOutside);
return () => document.removeEventListener('mousedown', handleClickOutside);
}, [handler]);
return ref;
}
export default useClickOutside;
用法:
const ref = useClickOutside(() => setDropdownOpen(false));
return (
<div ref={ref}>
{dropdownOpen && <p>Dropdown Content</p>}
</div>
);
透過自訂 useMediaQuery 掛鉤,簡化了 React 中媒體查詢的管理,使響應式設計更有效率。
執行:
import { useState, useEffect } from "react";
function useMediaQuery(query: string): boolean {
const [matches, setMatches] = useState(false);
useEffect(() => {
const mediaQueryList = window.matchMedia(query);
const updateMatch = () => setMatches(mediaQueryList.matches);
updateMatch();
mediaQueryList.addEventListener('change', updateMatch);
return () => mediaQueryList.removeEventListener('change', updateMatch);
}, [query]);
return matches;
}
export default useMediaQuery;
用法:
const isMobile = useMediaQuery('(max-width: 768px)');
return <p>{isMobile ? 'Mobile View' : 'Desktop View'}</p>;
_自訂掛鉤展示了 React 的靈活性和強大功能,使程式碼更乾淨、可重複使用且更易於維護。
_
透過利用自訂掛鉤,開發人員可以簡化複雜的功能並建立可重複使用的高效程式碼。上面的例子展示了這些鉤子如何優雅地解決常見的挑戰。
我希望您覺得這有幫助!如果我們在LinkedIn上聯絡我會很高興 🚀
原文出處:https://dev.to/joodi/7-react-custom-hooks-i-always-use-as-a-front-end-developer-5i9