f in x
React Hooks: useState, useEffect, useRef, useMemo, useCallback — Complete Hands-On Guide
> cd .. / HUB_EDITORIALE
Sviluppo di siti web

React Hooks: useState, useEffect, useRef, useMemo, useCallback — Complete Hands-On Guide

[2026-06-04] Author: Meteora Web

Are your React components re-rendering for no reason? Or getting stale state inside effects? We've seen these issues countless times. At Meteora Web, we build React frontends paired with Laravel backends every day. This guide cuts the fluff: what each hook does, when to use it, and — more importantly — when to avoid it. Let's start with the real problem: most developers use hooks without understanding dependency arrays and memoization trade-offs.

useState — Reactive state, often misused

useState seems trivial, but 90% of bugs come from async updates and stale values.

Functional updates — always use them when new state depends on previous

// ❌ Wrong: lost update if clicked twice quickly
setCount(count + 1);

// ✅ Correct: always receives the latest value
setCount(prev => prev + 1);

Same applies to objects and arrays: never mutate, always create a new copy.

Lazy initial state — for expensive computations

const [data, setData] = useState(() => {
  const saved = localStorage.getItem('myData');
  return saved ? JSON.parse(saved) : [];
});

useEffect — Controlled side effects

Effects run after render. Wrong dependencies cause infinite loops or missed updates.

Sponsored Protocol

The dependency array — include everything you use inside

Skip one variable and you get a stale closure. Use the exhaustive-deps ESLint rule.

Cleanup — free resources

useEffect(() => {
  const timer = setInterval(() => console.log('tick'), 1000);
  return () => clearInterval(timer);
}, []);

Fetch pattern with cancellation

useEffect(() => {
  let cancelled = false;
  fetch('/api/data')
    .then(res => res.json())
    .then(data => { if (!cancelled) setData(data); });
  return () => { cancelled = true; };
}, []);

useRef — Mutable container that doesn't cause re-renders

Two main uses:

DOM references

const inputRef = useRef(null);
// later: inputRef.current.focus();

Storing values without triggering renders

const prevCountRef = useRef();
useEffect(() => { prevCountRef.current = count; });
const prevCount = prevCountRef.current;

useMemo — Memoizing expensive values

Returns a cached value that recalculates only when dependencies change. Use for heavy computations like filtering large arrays or formatting data.

Sponsored Protocol

const filteredList = useMemo(
  () => items.filter(item => item.active),
  [items]
);

Don't overuse it: it adds memory overhead. Profile first, memoize second.

useCallback — Stable function references

Returns the same function instance unless dependencies change. Critical when passing callbacks to child components optimized with React.memo.

const handleClick = useCallback(() => {
  doSomething(id);
}, [id]);

return ;

Without it, every parent render creates a new function reference, causing the child to re-render unnecessarily.

Sponsored Protocol

Putting It All Together

function SearchForm({ onSubmit }) {
  const [query, setQuery] = useState('');
  const inputRef = useRef(null);
  const debouncedQuery = useDebounce(query, 300);

  const handleSubmit = useCallback((e) => {
    e.preventDefault();
    onSubmit(debouncedQuery);
  }, [debouncedQuery, onSubmit]);

  const searchResults = useMemo(() => {
    if (!debouncedQuery) return [];
    return expensiveSearch(debouncedQuery);
  }, [debouncedQuery]);

  useEffect(() => {
    if (query) inputRef.current?.focus();
  }, [query]);

  return (
    
setQuery(e.target.value)} /> ); }

Common Mistakes — The Blacklist

  • Stale closure: using a variable inside useEffect without listing it in dependencies. Include it or use useRef if intentional.
  • Objects/arrays as dependencies: React compares by reference. Create stable references with useMemo.
  • Premature memoization: don't optimize before measuring. First make it work, then profile.
  • Missing cleanup: subscriptions, timers, listeners — always clean up.

In a Nutshell — What to Do Now

  1. Audit your useEffect: check that all variables used inside are in the dependency array.
  2. Add cleanup for every subscription (setInterval, addEventListener, cancelled fetch).
  3. Replace direct useState updates with functional form when new state depends on old.
  4. Profile renders with React DevTools: where you see unnecessary re-renders, consider useMemo/useCallback on children with React.memo.
  5. Remove unused memoization: if it doesn't improve performance, delete it.

At Meteora Web, we believe in writing clean code first, optimizing second. Hooks are powerful when understood deeply. For more, check the official React documentation.

Meteora Web

> AUTHOR_EXTRACTED

Meteora Web

[ Read Full Dossier ]

> METEORA_WEB // DIGITAL AGENCY

We build the digital presence your business deserves.

Websites, social media, online advertising, e-commerce and high-performance hosting, engineered with method by computer engineers in Sciacca, for all of Italy.

> MW_JOURNAL

> READ_ALL()