A custom Hook is a JavaScript function that uses React Hooks to reuse stateful logic across components.
Its name must start with use, and it must follow the Rules of Hooks.
function useCount() {const [count, setCount] = useState(0)const increment = () => {setCount(c => c + 1)}return { count, increment }}
Use it like any other Hook:
function Counter() {const { count, increment } = useCount()return <button onClick={increment}>{count}</button>}
Each call to useCount() has its own state. Custom Hooks share logic, not state, unless they connect to a shared store or Context.
Consider this effect:
useEffect(() => {const id = setInterval(increment, 1000)return () => clearInterval(id)}, [increment])
If increment is declared directly inside a custom Hook, a new function is created on each render.
Because its reference changes, React cleans up the previous effect and runs it again after each render.
For an interval, that means repeatedly resetting the timer.
useCallbackfunction useCount() {const [count, setCount] = useState(0)const increment = useCallback(() => {setCount(c => c + 1)}, [])return { count, increment }}
The functional state update setCount(c => c + 1) means the callback does not need to capture count, so the empty dependency array is correct.
Now increment retains the same reference between renders, allowing effects that depend on it to avoid unnecessary resynchronization.
Important: useCallback is useful when function identity matters. It is not necessary for every event handler.
Memoization reuses a previously calculated result while its dependencies remain unchanged.
React provides two related Hooks:
useMemo caches a calculated value.useCallback caches a function reference.const total = useMemo(() => calculateTotal(items), [items])const handleClick = useCallback(() => {submitForm(formData)}, [formData])
These Hooks can help avoid expensive calculations or unnecessary re-renders when passed to memoized child components.