const [items, setItems] = useState(['apple', 'banana']); async function addItem(newItem) { setItems([...items, newItem]); // optimistic update await fetch('/api/add', { method: 'POST', body: JSON.stringify({ item: newItem }) }); // no rollback on failure here } // User clicks button to add 'orange'
Optimistic updates show the new data immediately to improve user experience. The UI updates before the server confirms the change.
const [items, setItems] = useState(['cat', 'dog']); async function addPet(pet) { setItems([...items, pet]); // optimistic update try { const res = await fetch('/api/addPet', { method: 'POST', body: JSON.stringify({ pet }) }); if (!res.ok) throw new Error('Failed'); } catch { // no rollback } } // addPet('rabbit') is called but server returns error
Without rollback, the UI keeps the optimistic change even if the server rejects it, so 'rabbit' stays in the list.
const [items, setItems] = useState([]); async function addItem(item) { setItems([]); // clear list first setItems([...items, item]); // optimistic update await fetch('/api/add', { method: 'POST', body: JSON.stringify({ item }) }); } // User adds 'pear'
Clearing the list causes the UI to render empty briefly, then re-render with the new item, causing flicker.
Option B saves old state, updates optimistically, and restores old state only on error.
Other options either restore state unconditionally or clear incorrectly.
Optimistic updates improve perceived speed by updating UI immediately, making apps feel more responsive.
They do not guarantee consistency or reduce server load directly.
