eduardweb.
Hooks & PatternsIntermediar#state-management#react#frontend#react-19

Cum am scăpat de loading spinners folosind useOptimistic în React 19

De Delia Petre, 15 iul. 2026 · 13 vizualizări · 2 like-uri

Postat 15 iul. 2026
typescript
import { useOptimistic, useRef } from 'react';

type Comment = { id: string; text: string; sending?: boolean };

export function CommentList({
  initialComments,
  addCommentAction
}: {
  initialComments: Comment[];
  addCommentAction: (formData: FormData) => Promise<void>;
}) {
  const formRef = useRef<HTMLFormElement>(null);
  const [optimisticComments, setOptimisticComment] = useOptimistic(
    initialComments,
    (state, newCommentText: string) => [
      ...state,
      { id: Math.random().toString(), text: newCommentText, sending: true }
    ]
  );

  async function action(formData: FormData) {
    const text = formData.get("comment") as string;
    formRef.current?.reset();
    setOptimisticComment(text);
    try {
      await addCommentAction(formData);
    } catch (e) {
      // Rollback-ul se face automat când promisiunea se termină cu eroare
      // și React re-randează componenta cu starea reală de pe server.
    }
  }

  return (
    <form action={action} ref={formRef}>
      <input type="text" name="comment" required placeholder="Scrie un comentariu..." />
      <button type="submit">Trimite</button>
      <ul>
        {optimisticComments.map(c => (
          <li key={c.id} style={{ opacity: c.sending ? 0.5 : 1 }}>
            {c.text} {c.sending && "(se trimite...)"}
          </li>
        ))}
      </ul>
    </form>
  );
}

Salutare! Zilele astea am refăcut modulul de feedback pentru un client cu vreo 15k utilizatori activi. Înainte, când un user lăsa un comentariu, aveam clasicul spinner: dădeai click, așteptai după API vreo 800ms, apoi apărea textul în listă. Un UX obosit, de anii 2010. Am trecut proiectul pe React 19 și am zis să testez noul hook useOptimistic. Rezultatul? Interfața se mișcă instant, iar utilizatorul nu mai simte latența bazei de date.

Până acum, ca să faci asta ca la carte, trebuia să te complici cu Redux, React Query sau să-ți scrii singur un boilerplate imens în useState. Trebuia să salvezi starea veche, să adaugi item-ul nou "pe fals", iar pe catch-ul de eroare să faci rollback manual. O durere de cap pe care o evitam des din pură comoditate.

useOptimistic rezolvă fix problema asta, dar vine la pachet cu un mod de gândire destul de specific. Merge mână în mână cu Server Actions și Form Actions. Practic, îi dai o stare de bază și o funcție de update care rulează instant, înainte ca request-ul real să se termine.

Cum arată implementarea

În exemplul de mai jos, pe care l-am simplificat din codul meu de producție, avem o listă de comentarii. Când trimiți formularul, apelăm setOptimisticComment. UI-ul se randează imediat cu noul comentariu marcat ca "se trimite" (îi scădem opacitatea la 0.5 ca să fie clar).

React rulează acțiunea asincronă în fundal. Dacă serverul răspunde cu succes, starea reală se updatează și înlocuiește starea optimistă. Dacă crapă API-ul, React face rollback automat la starea anterioară, fără să scrii tu vreo linie de cod suplimentară pentru asta.

Trade-off-uri de care trebuie să știi

Totul sună perfect în teorie, dar am dat de câteva limitări în practică. useOptimistic este genial pentru adăugări simple, ștergeri sau toggle-uri de tip like/dislike.

Totuși, dacă ai scenarii complexe unde ordinea elementelor depinde strict de ID-urile generate de baza de date sau dacă userul face spam de click-uri pe o conexiune 3G extrem de lentă, starea poate deveni temporar confuză pentru utilizator. De asemenea, dacă nu folosești arhitectura de Form Actions din React 19, integrarea acestui hook devine destul de forțată și își pierde din eleganță.

La mine a eliminat cam 30% din codul de gestionare a stării pe care îl scriam manual pentru interacțiuni asincrone. Merită efortul de migrare dacă vrei o aplicație care să se simtă "snappy".

Voi ați apucat să-l folosiți în producție sau încă așteptați să se stabilizeze ecosistemul din jurul React 19?

Răspunsuri 0

Se încarcă răspunsurile…

Loghează-te pentru a răspunde

Doar membrii comunității pot lăsa comentarii.