React - Custom Hooks
Why Custom Hooks?
Encapsulate reusable stateful logic as functions starting with use
.
Try it: useLocalStorage
View source
const { useState, useEffect } = React;
function useLocalStorage(key, initial){
const [value, setValue] = useState(() => {
try { const v = localStorage.getItem(key); return v != null ? JSON.parse(v) : initial; }
catch { return initial; }
});
useEffect(() => {
try { localStorage.setItem(key, JSON.stringify(value)); } catch {}
}, [key, value]);
return [value, setValue];
}
function App(){
const [name, setName] = useLocalStorage('name', '');
return (
<div>
<label>Name: <input value={name} onChange={e => setName(e.target.value)} /></label>
<p>Stored value persists across refreshes.</p>
</div>
);
}
ReactDOM.createRoot(document.getElementById('try-custom-hooks')).render(<App />);
Syntax primer (for newcomers)
- Custom hooks are plain functions whose name starts with
use
(e.g.,useLocalStorage
). - They can call other hooks and return values just like React hooks.
- Follow the Rules of Hooks: call at the top level of components/hooks (not conditionally).
Vocabulary
- Hook: React function that adds features like state or effects.
- Custom hook: Your reusable function that calls hooks and returns values.
Common pitfalls
- Naming: custom hooks must start with
use
so linters can enforce the Rules of Hooks. - Hidden dependencies: document any assumptions (e.g., localStorage availability) and handle errors.
- Over-generalization: start specific; generalize only when you have multiple real use cases.
Exercises
- Write
useToggle(initial)
that returns[value, toggle]
. - Write
useInterval(callback, delay)
with proper setup/cleanup in an effect. - Refactor a component with repeated logic to use a custom hook and compare readability.
Checks for Understanding
- What are the benefits of extracting logic into a custom hook?
- Can custom hooks render JSX? Why or why not?
Show answers
- Reusability, testability, and clearer components by separating concerns.
- No; custom hooks are functions that encapsulate logic and return values, not UI.