f in x
React Hooks: useState, useEffect, useRef, useMemo, useCallback — Complete Hands-On Guide
> cd .. / HUB_EDITORIALE
Analisi dei dati e metriche

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

[2026-06-04] Author: Ing. Calogero Bono

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.

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.

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.

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.

Sponsored Protocol

Ing. Calogero Bono

> AUTHOR_EXTRACTED

Ing. Calogero Bono

Co-founder di Meteora Web. Ingegnere informatico, sviluppo ecosistemi digitali ad alte prestazioni. AI, automazione, SEO tecnica e infrastrutture web. Scrivo di tecnologia per rendere complesso… semplice.

[ Read Full Dossier ]

Hai bisogno di applicare questa strategia?

Esegui il protocollo di contatto per iniziare un progetto con noi.

> INIZIA_PROGETTO

Sponsored

> MW_JOURNAL

> READ_ALL()