← Back
Edit Post
Title
Description
Updater functions for rapid clicks, data-pending for parent styling, ArchiveButton pattern.
Content
Markdown supported
# useOptimistic `useOptimistic` provides immediate UI feedback while an action runs in the background. ## Example: ArchiveButton with Pending State From `app/dashboard/_components/ArchiveButton.tsx`: ```tsx 'use client'; import { useOptimistic } from 'react'; export function ArchiveButton({ slug, archived }) { const [optimisticArchived, setOptimisticArchived] = useOptimistic(archived); const isPending = optimisticArchived !== archived; return ( <form data-pending={isPending || undefined} action={async () => { // Use updater function to read current pending state let newValue; setOptimisticArchived(current => { newValue = !current; return newValue; }); await toggleArchivePost(slug, newValue); }} > <button type="submit"> {optimisticArchived ? 'Unarchive' : 'Archive'} </button> </form> ); } ``` ## Why Use Updater Functions? When users click rapidly, multiple actions queue up. Each closure captures the same `optimisticArchived` value: ```tsx // ❌ Stale closure - both clicks see archived=false setOptimisticArchived(!optimisticArchived); // false → true setOptimisticArchived(!optimisticArchived); // false → true (stale!) // ✅ Updater function reads from React's queue setOptimisticArchived(current => !current); // false → true setOptimisticArchived(current => !current); // true → false ``` ## Styling Parent Elements with CSS :has() Expose pending state via `data-pending` attribute. Parent Server Components can style based on this using Tailwind's `has-data-pending:` variant: ```tsx // PostList.tsx (Server Component - no 'use client' needed!) <Card className="has-data-pending:animate-pulse has-data-pending:bg-muted/70"> <ArchiveButton slug={post.slug} archived={post.archived} /> </Card> ``` ## How It Works 1. User submits the form 2. `setOptimisticArchived` immediately updates the UI and sets `data-pending` 3. CSS `:has([data-pending])` triggers parent styles (pulse animation) 4. The Server Function runs in the background 5. When complete, the real `archived` prop replaces the optimistic value 6. `data-pending` is removed, styles revert ## Important: Requires Action Context The optimistic setter must be called inside an Action—a function passed to an action prop or wrapped in `startTransition`. Form `action` props are automatically called inside `startTransition`. Use for actions with high success rates: toggles, likes, bookmarks.
Published
Save Changes
Cancel