Search sections or pages...
Search sections or pages...
Rafly Aziz Abdillah
Waktu ngoding React, gue sering banget nemuin pattern yang sama berulang-ulang di setiap project. Daripada nulis logic yang sama terus-terusan, mending bikin custom hooks aja yang bisa dipake berkali-kali. Nah, ini dia 5 custom hooks favorit gue yang worth it banget buat dicoba!
Pernah bikin fitur search dengan auto-complete? Setiap kali user ngetik, langsung trigger API call. Boros banget! Bayangin user ngetik "javascript" - itu udah 10 API calls cuma buat 10 huruf doang.
import { useState, useEffect } from 'react';
function useDebounce(value, delay = 500) {
const [debouncedValue, setDebouncedValue] = useState(value);
useEffect(() => {
const handler = setTimeout(() => {
setDebouncedValue(value);
}, delay);
return () => clearTimeout(handler);
}, [value, delay]);
return debouncedValue;
}
export default useDebounce;function SearchBox() {
const [query, setQuery] = useState('');
const debouncedQuery = useDebounce(query, 500);
useEffect(() => {
if (debouncedQuery) {
fetch(`/api/search?q=${debouncedQuery}`)
.then(res => res.json())
.then(data => console.log(data));
}
}, [debouncedQuery]);
return <input value={query} onChange={e => setQuery(e.target.value)} />;
}Pro tip: Delay 300-500ms buat search, 1000-2000ms buat auto-save.
Nyimpen data ke localStorage itu ribet. Harus JSON.parse(), JSON.stringify(), plus handle error. Capek deh!
import { useState } from 'react';
function useLocalStorage(key, initialValue) {
const [storedValue, setStoredValue] = useState(() => {
try {
const item = window.localStorage.getItem(key);
return item ? JSON.parse(item) : initialValue;
} catch {
return initialValue;
}
});
const setValue = (value) => {
const valueToStore = value instanceof Function ? value(storedValue) : value;
setStoredValue(valueToStore);
window.localStorage.setItem(key, JSON.stringify(valueToStore));
};
return [storedValue, setValue];
}
export default useLocalStorage;function ThemeToggle() {
const [theme, setTheme] = useLocalStorage('theme', 'light');
return (
<button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>
Current Theme: {theme}
</button>
);
}Perfect buat nyimpen user preferences, theme, atau cart items!
Setiap fetch data harus bikin state loading, error, dan data. Bosen nulis berulang-ulang!
import { useState, useEffect } from 'react';
function useFetch(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const fetchData = async () => {
setLoading(true);
try {
const res = await fetch(url);
if (!res.ok) throw new Error('Fetch gagal');
setData(await res.json());
} catch (err) {
setError(err.message);
} finally {
setLoading(false);
}
};
fetchData();
}, [url]);
return { data, loading, error };
}
export default useFetch;function UserList() {
const { data, loading, error } = useFetch('/api/users');
if (loading) return <p>Loading...</p>;
if (error) return <p>Error: {error}</p>;
return (
<ul>
{data.map(user => <li key={user.id}>{user.name}</li>)}
</ul>
);
}Bonus: Bisa dikembangin dengan abort controller buat cancel request!
Nulis setState(prev => !prev) berkali-kali itu redundant banget.
import { useState, useCallback } from 'react';
function useToggle(initialValue = false) {
const [value, setValue] = useState(initialValue);
const toggle = useCallback(() => setValue(prev => !prev), []);
const setTrue = useCallback(() => setValue(true), []);
const setFalse = useCallback(() => setValue(false), []);
return [value, toggle, setTrue, setFalse];
}
export default useToggle;function Modal() {
const [isOpen, toggle, open, close] = useToggle(false);
return (
<div>
<button onClick={open}>Buka Modal</button>
{isOpen && (
<div className="modal">
<p>Ini konten modal</p>
<button onClick={close}>Tutup</button>
</div>
)}
</div>
);
}Gampang kan? Tinggal panggil
toggle(),open(), atauclose().
Nutup dropdown atau modal pas user klik di luar itu tricky. Harus manage event listener dengan benar.
import { useEffect, useRef } from 'react';
function useClickOutside(handler) {
const ref = useRef(null);
useEffect(() => {
const handleClick = (event) => {
if (ref.current && !ref.current.contains(event.target)) {
handler();
}
};
document.addEventListener('mousedown', handleClick);
return () => document.removeEventListener('mousedown', handleClick);
}, [handler]);
return ref;
}
export default useClickOutside;function Dropdown() {
const [isOpen, setIsOpen] = useState(false);
const dropdownRef = useClickOutside(() => setIsOpen(false));
return (
<div ref={dropdownRef}>
<button onClick={() => setIsOpen(!isOpen)}>Menu</button>
{isOpen && (
<ul className="dropdown-menu">
<li>Option 1</li>
<li>Option 2</li>
<li>Option 3</li>
</ul>
)}
</div>
);
}Essential buat dropdown, modal, dan sidebar!
Kelima custom hooks ini bener-bener ngebantu workflow coding sehari-hari:
Tips: Simpen semua hooks di folder
src/hooks/biar project-mu makin rapi!
Happy coding! 🚀
Comments(0)