typescript 49 lines · 8 steps

Optimistic UI updates in a React hook

A custom hook toggles a todo instantly, then reconciles or rolls back based on the server's response.

Explained by highlit
1import { useState, useCallback } from 'react';
2 
3type Todo = {
4 id: string;
5 title: string;
6 completed: boolean;
7};
8 
9export function useToggleTodo(initial: Todo[]) {
10 const [todos, setTodos] = useState(initial);
11 const [error, setError] = useState<string | null>(null);
12 
13 const toggle = useCallback(async (id: string) => {
14 const previous = todos;
15 const target = todos.find((t) => t.id === id);
16 if (!target) return;
17 
18 const nextCompleted = !target.completed;
19 
20 setTodos((current) =>
21 current.map((t) =>
22 t.id === id ? { ...t, completed: nextCompleted } : t,
23 ),
24 );
25 setError(null);
26 
27 try {
28 const res = await fetch(`/api/todos/${id}`, {
29 method: 'PATCH',
30 headers: { 'Content-Type': 'application/json' },
31 body: JSON.stringify({ completed: nextCompleted }),
32 });
33 
34 if (!res.ok) {
35 throw new Error(`Request failed: ${res.status}`);
36 }
37 
38 const saved: Todo = await res.json();
39 setTodos((current) =>
40 current.map((t) => (t.id === id ? saved : t)),
41 );
42 } catch (err) {
43 setTodos(previous);
44 setError(err instanceof Error ? err.message : 'Update failed');
45 }
46 }, [todos]);
47 
48 return { todos, error, toggle };
49}
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1Optimistic updates apply the change immediately and treat the network round-trip as confirmation, not a prerequisite.
  2. 2Capturing prior state before mutating gives you a clean rollback path when the request fails.
  3. 3Returning both data and error from a hook lets components render success and failure from one source of truth.

Related explainers

Share this explainer

Here's the card — post it anywhere.

Optimistic UI updates in a React hook — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code