Custom Hooks
What Are Custom Hooks?
Custom hooks are regular JavaScript functions that use hooks inside them. Convention: the name must start with use.
function useCounter(initialValue = 0) {
const [count, setCount] = React.useState(initialValue);
const increment = () => setCount(c => c + 1);
const decrement = () => setCount(c => c - 1);
const reset = () => setCount(initialValue);
return { count, increment, decrement, reset };
}
Why Custom Hooks?
- Reuse logic across components
- Reduce code duplication
- Separate concerns
- Make code easier to test
Example: useFetch
function useFetch(url) {
const [data, setData] = React.useState(null);
const [loading, setLoading] = React.useState(true);
const [error, setError] = React.useState(null);
React.useEffect(() => {
let cancelled = false;
setLoading(true);
fetch(url)
.then(res => {
if (!res.ok) throw new Error('Failed to load');
return res.json();
})
.then(data => {
if (!cancelled) {
setData(data);
setLoading(false);
}
})
.catch(err => {
if (!cancelled) {
setError(err.message);
setLoading(false);
}
});
return () => { cancelled = true; };
}, [url]);
return { data, loading, error };
}
// Usage
function UserProfile({ userId }) {
const { data: user, loading, error } = useFetch(`/api/users/${userId}`);
if (loading) return <p>Loading...</p>;
if (error) return <p>Error: {error}</p>;
return <h2>{user.name}</h2>;
}
Example: useLocalStorage
function useLocalStorage(key, initialValue) {
const [value, setValue] = React.useState(() => {
try {
const item = localStorage.getItem(key);
return item ? JSON.parse(item) : initialValue;
} catch {
return initialValue;
}
});
React.useEffect(() => {
localStorage.setItem(key, JSON.stringify(value));
}, [key, value]);
return [value, setValue];
}
// Usage
function Settings() {
const [theme, setTheme] = useLocalStorage('theme', 'light');
const [lang, setLang] = useLocalStorage('language', 'id');
return (
<div>
<select value={theme} onChange={e => setTheme(e.target.value)}>
<option value="light">Light</option>
<option value="dark">Dark</option>
</select>
<select value={lang} onChange={e => setLang(e.target.value)}>
<option value="id">Indonesia</option>
<option value="en">English</option>
</select>
</div>
);
}
Example: useToggle
function useToggle(initialValue = false) {
const [value, setValue] = React.useState(initialValue);
const toggle = () => setValue(v => !v);
const setTrue = () => setValue(true);
const setFalse = () => setValue(false);
return { value, toggle, setTrue, setFalse };
}
// Usage
function Modal() {
const { value: isOpen, toggle, setFalse: close } = useToggle();
return (
<div>
<button onClick={toggle}>Open Modal</button>
{isOpen && (
<div className="modal">
<h2>Modal Open</h2>
<button onClick={close}>Close</button>
</div>
)}
</div>
);
}
Custom Hook Rules
- Always start with
use - Can call other hooks inside
- Can return any value
- Can accept parameters
Custom hooks let us share logic effectively. Next we will study React Router for navigation between pages.