import { useOptimistic, useTransition, useRef } from 'react';
type Comment = {
id: string;
text: string;
isSending?: boolean;
};
interface CommentFormProps {
initialComments: Comment[];
onAddCommentOnServer: (text: string) => Promise<Comment>;
}
export function CommentForm({ initialComments, onAddCommentOnServer }: CommentFormProps) {
const [isPending, startTransition] = useTransition();
const formRef = useRef<HTMLFormElement>(null);
const [optimisticComments, setOptimisticComments] = useOptimistic(
initialComments,
(currentState, newCommentText: string) => [
...currentState,
{ id: Math.random().toString(), text: newCommentText, isSending: true }
]
);
const handleAction = async (formData: FormData) => {
const text = formData.get('comment') as string;
if (!text.trim()) return;
formRef.current?.reset();
startTransition(async () => {
setOptimisticComments(text);
try {
await onAddCommentOnServer(text);
} catch (error) {
console.error('Rollback-ul se execută automat acum:', error);
}
});
};
return (
<div className="p-4 max-w-md">
<form ref={formRef} action={handleAction} className="flex gap-2 mb-4">
<input
name="comment"
className="border p-2 rounded flex-1"
placeholder="Scrie un comentariu..."
required
/>
<button
type="submit"
disabled={isPending}
className="bg-blue-600 text-white px-4 py-2 rounded disabled:opacity-50"
>
Trimite
</button>
</form>
<ul className="space-y-2">
{optimisticComments.map((comment) => (
<li
key={comment.id}
className={`p-2 rounded border ${comment.isSending ? 'opacity-50 bg-gray-50 italic' : 'bg-white'}`}
>
{comment.text} {comment.isSending && ' (se trimite...)'}
</li>
))}
</ul>
</div>
);
}Am implementat recent noul hook useOptimistic din React 19 pe o secțiune de comentarii la un proiect cu vreo 15k utilizatori activi lunar. Rezultatul? Am redus latența percepută de utilizator de la 1.2 secunde (timpul mediu de răspuns al API-ului nostru pe conexiuni mobile) la fix zero.
Până acum, ca să faci asta ca la carte, trebuia să scrii o tonă de cod plictisitor. Puneai starea locală, trimiteai request-ul, iar dacă dădea eroare, trebuia să prinzi excepția și să faci rollback manual în catch block. Era extrem de ușor să scapi un bug și să lași UI-ul desincronizat cu baza de date.
Cum simplifică React 19 toată povestea asta
Ideea din spatele useOptimistic este extrem de simplă. Îi dai o stare de bază (care vine de obicei din baza de date sau din props) și o funcție de tip reducer care definește cum se modifică starea temporar, până când serverul confirmă scrierea.
Pentru ca magia să funcționeze, React are nevoie de un context de asincronism. Aici intră în scenă useTransition (sau noile Form Actions). Cât timp funcția din interiorul tranziției rulează (adică promisiunea este în starea pending), React știe să păstreze starea optimistă activă.
În momentul în care promisiunea se rezolvă — fie cu succes, fie cu eroare — framework-ul face automat curățenie, aruncă starea temporară și revine la starea reală propagată de la server. Dacă API-ul dă eroare, comentariul trimis pur și simplu dispare instant din listă, fără ca tu să scrii vreun rând de cod pentru rollback.
Un exemplu complet și funcțional
În exemplul de mai jos, poți vedea cum legăm useOptimistic de o acțiune de formular. Cât timp request-ul este în desfășurare, comentariul nou apare în listă cu o opacitate redusă, oferind un feedback vizual excelent utilizatorului.
Trade-off-ul sincer: Când devine problematic?
Deși sună ca o soluție universală, m-am lovit rapid de o limitare majoră în faza de testare. useOptimistic funcționează impecabil doar dacă datele tale temporare sunt identice structural cu cele care vin de la server după salvare.
Dacă API-ul tău face procesări complexe pe backend — de exemplu, dacă serverul generează ID-uri unice, formatează textul prin Markdown, sau aplică filtre de cenzură — utilizatorul va vedea un mic „flash” vizual deranjant. Comentariul apare instant într-o formă brută, iar când vine răspunsul real de la server, se modifică brusc în forma procesată.
Pentru acțiuni simple precum liste de comentarii, butoane de „Like”, adăugare în coș sau toggle-uri de status, hook-ul ăsta este genial și salvează sute de linii de cod de gestiune a stării.
Voi ați apucat să testați React 19 în producție sau încă așteptați să se mai așeze praful peste ecosistemul de librării?