Optimistic updates make your app feel faster by showing changes right away before the server confirms them.
Optimistic updates pattern in NextJS
Start learning this pattern below
Jump into concepts and practice - no test required
const [data, setData] = useState(initialData); async function updateData(newData) { const previousData = data; // 1. Update UI immediately setData(newData); try { // 2. Send update to server await fetch('/api/update', { method: 'POST', body: JSON.stringify(newData), headers: { 'Content-Type': 'application/json' } }); } catch (error) { // 3. Revert UI if server fails setData(previousData); } }
Update the UI state first, then send the server request.
If the server fails, revert the UI to the old state to keep data correct.
const [count, setCount] = useState(0); function like() { const previousCount = count; setCount(previousCount + 1); // update UI immediately fetch('/api/like', { method: 'POST' }).catch(() => setCount(previousCount)); // revert if error }
const [items, setItems] = useState(['apple', 'banana']); function addItem(newItem) { const previousItems = items; setItems([...previousItems, newItem]); // show new item right away fetch('/api/add', { method: 'POST', body: JSON.stringify(newItem), headers: { 'Content-Type': 'application/json' } }) .catch(() => setItems(previousItems)); // undo if error }
This Next.js component lets you add todos instantly. It updates the list right away, sends the new todo to the server, and if the server fails, it removes the new todo and shows an alert.
It uses accessible labels and keyboard support for better user experience.
import { useState } from 'react'; export default function OptimisticUpdate() { const [todos, setTodos] = useState(['Learn Next.js', 'Build app']); const [input, setInput] = useState(''); async function addTodo() { if (!input.trim()) return; const previousTodos = todos; const newTodos = [...todos, input]; setTodos(newTodos); // update UI immediately try { const res = await fetch('/api/todos', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ todo: input }) }); if (!res.ok) throw new Error('Failed to save'); setInput(''); // clear input on success } catch { setTodos(previousTodos); // revert UI if error alert('Failed to add todo. Please try again.'); } } return ( <main> <h1>My Todos</h1> <ul> {todos.map((todo, i) => <li key={i}>{todo}</li>)} </ul> <input aria-label="New todo" value={input} onChange={e => setInput(e.target.value)} onKeyDown={e => e.key === 'Enter' && addTodo()} /> <button onClick={addTodo} aria-label="Add todo">Add</button> </main> ); }
Always handle errors to avoid showing wrong data.
Optimistic updates improve user experience but need careful rollback logic.
Use accessible labels and keyboard events for better usability.
Optimistic updates show changes immediately to make apps feel faster.
Update UI first, then confirm with server, and revert if needed.
Good error handling and accessibility improve the pattern's success.
Practice
optimistic updates pattern in Next.js?Solution
Step 1: Understand the purpose of optimistic updates
Optimistic updates aim to make the app feel faster by showing changes immediately.Step 2: Compare UI update timing
Instead of waiting for the server, the UI updates first, then confirms or reverts based on server response.Final Answer:
Update the UI immediately before server confirmation to improve user experience -> Option AQuick Check:
Optimistic updates = Immediate UI update [OK]
- Waiting for server before UI update
- Reloading entire page unnecessarily
- Disabling user input during update
Solution
Step 1: Identify optimistic update flow
Optimistic update means updating UI state immediately withsetState.Step 2: Confirm API call and handle errors
Send API request after UI update, and revert state if the request fails.Final Answer:
CallsetStateto update UI, then send API request, revert on error -> Option CQuick Check:
Update state first, then API call [OK]
- Waiting for API before updating state
- Using useEffect incorrectly for optimistic update
- Reloading page instead of updating state
const [likes, setLikes] = useState(0);
async function handleLike() {
setLikes(likes + 1);
try {
await fetch('/api/like', { method: 'POST' });
} catch {
setLikes(likes); // revert on error
}
}What will the UI show if the API call fails?
Solution
Step 1: Analyze optimistic update behavior
The UI increments likes immediately by 1 usingsetLikes(likes + 1).Step 2: Check error handling
If the API call fails,setLikes(likes)resets likes to the original value before increment.Final Answer:
The likes count reverts to the original value -> Option DQuick Check:
API error triggers revert to old likes [OK]
- Assuming UI stays incremented after failure
- Resetting likes to zero incorrectly
- Incrementing likes twice by mistake
const [count, setCount] = useState(0);
async function increment() {
setCount(count + 1);
try {
await fetch('/api/increment', { method: 'POST' });
} catch {
setCount(count - 1);
}
}What is the bug causing the revert to fail?
Solution
Step 1: Understand state closure issue
Thecountvariable insidecatchis the old value before increment.Step 2: Explain why revert fails
Subtracting 1 from stalecountdoes not revert to original becausecountwas already incremented in UI.Final Answer:
Using stalecountvalue insidecatchblock -> Option AQuick Check:
State closure causes revert failure [OK]
- Expecting setState to be async
- Ignoring stale closure of state variable
- Wrong HTTP method for API call
Solution
Step 1: Apply optimistic update pattern
Update UI immediately by adding comment to state to improve responsiveness.Step 2: Handle server confirmation and errors
Send API request; if it fails, remove the comment from UI to keep data consistent.Final Answer:
Add comment to UI state immediately, send API request, remove comment if API fails -> Option BQuick Check:
UI update first, revert on error [OK]
- Waiting for API before UI update
- Adding comment only after success
- Reloading page instead of updating state
