Φόρτωση περιεχομένου...
Φόρτωση περιεχομένου...
Δημιουργήστε άμεσες μεταλλάξεις δεδομένων με τα React 19 useActionState και useOptimistic.
Στις παραδοσιακές web εφαρμογές, όταν ο χρήστης εκτελεί μια ενέργεια (π.χ. πατάει "Σήμανση ως Ολοκληρωμένο"), αναγκάζεται να περιμένει 300-800ms για να ταξιδέψει το HTTP αίτημα στον server, να αποθηκευτεί στη βάση και να επιστρέψει η απάντηση. Αυτή η καθυστέρηση κάνει το UI να μοιάζει αργό και δυσκίνητο.
Με το Next.js 16 και τα νέα hooks του React 19 (useOptimistic και useActionState), μπορούμε να ενημερώσουμε το περιβάλλον χρήστη σε 0 milliseconds (Optimistic UI), ενώ ο ασύγχρονος συγχρονισμός με τον server εκτελείται στο παρασκήνιο.
Το Optimistic UI βασίζεται στην υπόθεση ότι η συντριπτική πλειοψηφία των ενεργειών του χρήστη (>99.9%) θα ολοκληρωθεί με επιτυχία:
useOptimistic του React 19Το hook useOptimistic δέχεται την πραγματική τιμή από τον server και μια συνάρτηση ανανέωσης (update function):
tsximport { useOptimistic } from "react" const [optimisticState, setOptimisticState] = useOptimistic( actualState, (currentState, updateValue) => { // Επιστρέφει τη νέα αισιόδοξη κατάσταση return updateValue } )
CompleteLessonButtonΣυνδυάζουμε το useActionState (για διαχείριση της εκκρεμούς κατάστασης και των αποτελεσμάτων του action) με το useOptimistic:
tsx"use client" import { useActionState, useOptimistic, startTransition } from "react" import { setLessonReadAction } from "@/actions/learning" import { CheckCircle2, Circle, Loader2 } from "lucide-react" interface CompleteButtonProps { initialCompleted: boolean courseSlug: string lessonSlug: string } export function CompleteLessonButton({ initialCompleted, courseSlug, lessonSlug, }: CompleteButtonProps) { // 1. Διαχείριση κατάστασης Server Action const [state, formAction, isPending] = useActionState(setLessonReadAction, { completed: initialCompleted, error: null, }) // 2. Αισιόδοξη ενημέρωση κατάστασης ολοκλήρωσης const [optimisticCompleted, setOptimisticCompleted] = useOptimistic( state.completed, (current, update: boolean) => update ) const handleToggle = () => { const nextValue = !optimisticCompleted // Εκκίνηση μετάβασης: Το UI αλλάζει σε 0ms startTransition(async () => { setOptimisticCompleted(nextValue) const formData = new FormData() formData.set("courseSlug", courseSlug) formData.set("lessonSlug", lessonSlug) formData.set("completed", String(nextValue)) await formAction(formData) }) } return ( <button onClick={handleToggle} disabled={isPending} className={`inline-flex items-center gap-2 px-3 py-1.5 rounded-lg text-xs font-medium transition-all ${ optimisticCompleted ? "bg-emerald-500/10 text-emerald-500 border border-emerald-500/30" : "bg-muted text-muted-foreground hover:bg-muted/80" }`} > {isPending ? ( <Loader2 className="h-3.5 w-3.5 animate-spin" /> ) : optimisticCompleted ? ( <CheckCircle2 className="h-3.5 w-3.5 text-emerald-500" /> ) : ( <Circle className="h-3.5 w-3.5 opacity-60" /> )} <span>{optimisticCompleted ? "Ολοκληρώθηκε" : "Σήμανση ως Ολοκληρωμένο"}</span> </button> ) }
Εάν ο server επιστρέψει σφάλμα (π.χ. { error: "Unauthorized" }), το React 19 αναγνωρίζει ότι η μετάβαση απέτυχε. Μόλις το isPending γίνει false, το useOptimistic επαναφέρει αυτόματα την τιμή στο πραγματικό state.completed, αποτρέποντας ασυνέπειες δεδομένων.
| Χαρακτηριστικό | Κλασικό Fetch / Loading Spinner | Server Action + useOptimistic |
|---|---|---|
| Αντιληπτή Ταχύτητα (Perceived Latency) | 300 - 800ms αναμονή με spinner | 0ms (Instant response) |
| Διαχείριση Rollback | Χειροκίνητη με try/catch & local state | Αυτόματη από το React reconciliation |
| Ανάγκη Client State Store (Redux/Zustand) | Συχνά απαραίτητη για κοινή χρήση | Μηδενική (State από Server Components) |