Every render creates new objects, arrays, and functions — even if their contents look identical. Two hooks let you skip that work when the inputs haven't changed:
useMemo — cache a computed value
const filtered = useMemo(
() => items.filter(i => i.includes(query)),
[items, query] // recompute only when these change
);
useCallback — cache a function reference
const handleChange = useCallback((e) => setQuery(e.target.value), []);
Rule of thumb: Don't reach for these by default. Use them when you have a measurably expensive computation or when a child component is wrapped in React.memo and needs stable props.
Your Task
Build a filterable fruit list:
- Items:
['apple', 'banana', 'cherry', 'date', 'elderberry', 'fig', 'grape']
<input id="filter"> controls the filter query
- Use
useMemo to compute the filtered list (case-insensitive match)
- Use
useCallback for the onChange handler
- Render matches in
<ul id="results"> with one <li> per item