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

Instant UI în React 19: Cum folosești useOptimistic fără să-ți strici starea

De Ana Ionescu, 20 iul. 2026 · 8 vizualizări · 2 like-uri

Postat 20 iul. 2026
typescript
import { useOptimistic, useTransition, useState } from 'react';

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

export function CommentSection({ initialComments }: { initialComments: Comment[] }) {
  const [comments, setComments] = useState<Comment[]>(initialComments);
  const [isPending, startTransition] = useTransition();

  const [optimisticComments, addOptimistic] = useOptimistic<Comment[], string>(
    comments,
    (state, newCommentText) => [
      ...state,
      { id: Math.random().toString(), text: newCommentText, sending: true }
    ]
  );

  async function handleAddComment(formData: FormData) {
    const commentText = formData.get("comment") as string;
    if (!commentText) return;

    startTransition(async () => {
      addOptimistic(commentText);
      try {
        const response = await fetch('/api/comments', {
          method: 'POST',
          body: JSON.stringify({ text: commentText })
        });
        if (!response.ok) throw new Error("Salvare eșuată");
        const savedComment = await response.json();
        setComments(prev => [...prev, savedComment]);
      } catch (err) {
        console.error("Rollback automat triggeruit de React:", err);
      }
    });
  }

  return (
    <div>
      {optimisticComments.map(c => (
        <p key={c.id} style={{ opacity: c.sending ? 0.5 : 1 }}>
          {c.text} {c.sending && '(se trimite...)'}
        </p>
      ))}
      <form action={handleAddComment}>
        <input name="comment" required />
        <button type="submit" disabled={isPending}>Trimite</button>
      </form>
    </div>
  );
}

React 19 aduce în sfârșit useOptimistic în API-ul stabil și, după ce l-am testat pe un modul de feedback cu vreo 5.000 de utilizatori activi, pot să zic că ne scapă de mult boilerplate. Până acum, ca să faci o interfață să se miște instant, trebuia să jonglezi manual cu stări temporare și rollback-uri scrise cu noduri în gât.

Cum ne complicam viața înainte

Am avut un proiect de e-commerce unde trebuia să dăm feedback instant la adăugarea în coș. Am scris zeci de linii de cod în Zustand doar ca să adaug un item cu un flag isPending: true, iar dacă API-ul dădea timeout după 5 secunde, trebuia să caut item-ul după un ID temporar și să-l scot. Era un coșmar de sincronizare. Dacă userul făcea trei acțiuni rapide, starea din client devenea o varză totală.

useOptimistic rezolvă fix asta. Îi dai starea reală (sursa adevărului) și o funcție care definește cum arată starea temporară în timp ce se execută o acțiune asincronă. React se ocupă de restul. Dacă acțiunea eșuează, React face rollback automat la starea anterioară.

Exemplul concret: Formularul de comentarii

Să luăm cazul clasic: un feed unde userul lasă un comentariu. Vrem ca textul să apară instant în listă, iar în fundal să trimitem request-ul la API.

Uită-te pe codul de mai jos. Ideea de bază e simplă:

  1. Avem starea reală comments venită din baza de date sau dintr-un hook părinte.
  2. Definim optimisticComments folosind noul hook.
  3. În interiorul acțiunii (folosind useTransition sau noile Server Actions), apelăm addOptimistic chiar înainte de a face fetch-ul.
  4. Dacă fetch-ul reușește, starea reală se updatează și înlocuiește varianta optimistă. Dacă pică, React aruncă starea optimistă la gunoi și revine la ce era înainte.

Prin abordarea asta, utilizatorul nu mai așteaptă acele 200-400ms de latență de rețea. Totul se întâmplă instantaneu pe ecran.

Trade-off-ul sincer: unde NU funcționează

Nu e totul roz și nu ar trebui să pui useOptimistic peste tot.

Merge brici pentru:

  • Butoane de Like/Inimioară.
  • Adăugare de comentarii simple.
  • Switch-uri de setări (on/off).

E groaznic pentru:

  • Fluxuri unde ordinea operațiunilor e critică și depinde strict de răspunsul serverului. De exemplu, dacă creezi o factură și vrei să generezi imediat un PDF pe baza ID-ului returnat de server. Dacă pui ID optimist "temp-id", userul va da click pe descărcare și va primi eroare pentru că "temp-id" nu există în baza de date reală.
  • Tranzacții financiare sau acțiuni cu risc ridicat. Acolo vrei ca userul să vadă un spinner clar și să aștepte confirmarea oficială a serverului.

Voi cum ați gestionat UI-ul optimist până acum? Ați făcut trecerea la React 19 sau încă vi se pare prea devreme pentru producție?

Răspunsuri 0

Se încarcă răspunsurile…

Loghează-te pentru a răspunde

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