javascript 44 lines · 7 steps

Optimistic like buttons in Next.js

A client component that flips the UI instantly with useOptimistic, then reconciles with a server action.

Explained by highlit
1'use client';
2 
3import { useOptimistic, useTransition } from 'react';
4import { toggleLike } from '@/app/actions/likes';
5 
6export function LikeButton({ postId, initialLiked, initialCount }) {
7 const [isPending, startTransition] = useTransition();
8 const [optimistic, setOptimistic] = useOptimistic(
9 { liked: initialLiked, count: initialCount },
10 (state, liked) => ({
11 liked,
12 count: state.count + (liked ? 1 : -1),
13 })
14 );
15 
16 function handleClick() {
17 const nextLiked = !optimistic.liked;
18 startTransition(async () => {
19 setOptimistic(nextLiked);
20 await toggleLike(postId, nextLiked);
21 });
22 }
23 
24 return (
25 <button
26 type="button"
27 onClick={handleClick}
28 disabled={isPending}
29 aria-pressed={optimistic.liked}
30 className="flex items-center gap-1.5 text-sm font-medium disabled:opacity-60"
31 >
32 <svg
33 viewBox="0 0 24 24"
34 className={`h-5 w-5 transition-colors ${
35 optimistic.liked ? 'fill-red-500 stroke-red-500' : 'fill-none stroke-current'
36 }`}
37 strokeWidth={2}
38 >
39 <path d="M12 21s-7.5-4.6-10-9.3C.7 8.9 2.2 5.5 5.5 5.5c2 0 3.4 1.2 4.5 2.8 1.1-1.6 2.5-2.8 4.5-2.8 3.3 0 4.8 3.4 3.5 6.2C19.5 16.4 12 21 12 21z" />
40 </svg>
41 <span>{optimistic.count}</span>
42 </button>
43 );
44}
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1useOptimistic lets you render a provisional state that automatically reverts if the underlying data doesn't confirm it.
  2. 2Wrapping a server action in startTransition keeps the UI responsive and exposes a pending flag for disabling controls.
  3. 3Deriving both the icon fill and count from one optimistic value keeps the whole button visually consistent during the round trip.

Related explainers

Share this explainer

Here's the card — post it anywhere.

Optimistic like buttons in Next.js — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code