7 Custom Hooks React "Thần thánh" mà mọi front-end developer nên nắm vững
Custom hooks không chỉ là một tiện ích trong React, mà còn là yếu tố thay đổi cuộc chơi trong việc viết code module và dễ bảo trì. Chúng cho phép lập trình viên đóng gói logic, quản lý trạng thái và sắp xếp các chức năng phức tạp một cách hiệu quả hơn bao giờ hết.
Bài viết này sẽ giới thiệu 7 custom hooks thiết yếu mà mọi lập trình viên nên có trong bộ công cụ của mình, cùng với hướng dẫn triển khai hiệu quả.
1. useFetch: Đơn giản hóa các lệnh gọi API
Việc lấy dữ liệu là một tác vụ phổ biến trong React. Hook useFetch sẽ tóm tắt logic lặp đi lặp lại, sắp xếp các lời gọi API và quản lý trạng thái một cách tinh tế.
Thực hiện:
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;
Cách sử dụng:
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>;
2. useDebounce: Tối ưu hóa hiệu suất
Xử lý input của người dùng thường xuyên, chẳng hạn như tìm kiếm hoặc các trường biểu mẫu, sẽ được thực hiện hiệu quả với hook debounce. Hook này giúp giảm render và gọi API không cần thiết.
Thực hiện:
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;
Cách sử dụng:
const [searchTerm, setSearchTerm] = useState('');
const debouncedSearch = useDebounce(searchTerm, 500);
useEffect(() => {
if (debouncedSearch) {
// Trigger API or other actions
}
}, [debouncedSearch]);
3. useToggle: Quản lý trạng thái Boolean dễ dàng
Việc quản lý trạng thái đóng/mở cho modals, dropdown hoặc chuyển đổi theme trở nên dễ dàng với hook useToggle, giúp code gọn gàng và tái sử dụng.
Thực hiện:
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;
Cách sử dụng:
const [isModalOpen, toggleModal] = useToggle();
return (
<div>
<button onClick={toggleModal}>Toggle Modal</button>
{isModalOpen && <p>Modal Content</p>}
</div>
);
4. useLocalStorage: Lưu trữ dữ liệu cục bộ
Việc lưu trữ và lấy dữ liệu từ localStorage trở nên liền mạch và tái sử dụng với hook useLocalStorage.
Thực hiện:
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;
Cách sử dụng:
const [theme, setTheme] = useLocalStorage('theme', 'light');
return (
<button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>
Toggle Theme
</button>
);
5. usePrevious: Theo dõi trạng thái trước đó
Theo dõi trạng thái trước đó của một giá trị là điều cần thiết cho việc so sánh và tạo hiệu ứng animation. Điều này có thể dễ dàng đạt được với hook usePrevious.
Thực hiện:
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;
Cách sử dụng:
const [count, setCount] = useState(0);
const prevCount = usePrevious(count);
return (
<p>
Now: {count}, Before: {prevCount}
</p>
);
6. useClickOutside: Phát hiện click outside
Hoàn hảo để đóng modals hoặc dropdown khi click bên ngoài, sử dụng hook useClickOutside giúp cải thiện trải nghiệm người dùng.
Thực hiện:
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;
Cách sử dụng:
const ref = useClickOutside(() => setDropdownOpen(false));
return (
<div ref={ref}>
{dropdownOpen && <p>Dropdown Content</p>}
</div>
);
7. useMediaQuery: Xử lý thiết kế Responsive
Quản lý media queries trong React được đơn giản hóa với hook useMediaQuery, giúp thiết kế responsive hiệu quả hơn.
Thực hiện:
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;
Cách sử dụng:
const isMobile = useMediaQuery('(max-width: 768px)');
return <p>{isMobile ? 'Mobile View' : 'Desktop View'}</p>;
Kết luận
Custom hooks thể hiện sự linh hoạt và sức mạnh của React, cho phép viết code sạch hơn, tái sử dụng và dễ bảo trì hơn. Bằng cách tận dụng custom hooks, lập trình viên có thể đơn giản hóa các chức năng phức tạp và tạo ra code tái sử dụng hiệu quả. Các ví dụ trên đã chứng minh cách các hook này giải quyết các thách thức phổ biến một cách tinh tế. Tôi hy vọng bài viết này hữu ích với bạn!
All rights reserved
Bình luận