React - Optimistic Updates
Overview
Estimated time: 20–30 minutes
Improve perceived performance by applying updates instantly and reconciling with server results.
Try it: Like button with optimistic UI
View source
function fakeServerToggleLike(current){
return new Promise((resolve, reject) => {
setTimeout(() => {
if (Math.random() < 0.8) resolve(!current); else reject(new Error('Network error'));
}, 500);
});
}
function App(){
const [liked, setLiked] = React.useState(false);
const [error, setError] = React.useState('');
const [pending, setPending] = React.useState(false);
async function onToggle(){
setError('');
const prev = liked; setLiked(!liked); setPending(true);
try{ const server = await fakeServerToggleLike(prev); setLiked(server); }
catch(e){ setLiked(prev); setError('Could not save, rolled back.'); }
finally{ setPending(false); }
}
return (
<div>
<button onClick={onToggle} disabled={pending}>{liked ? '♥ Liked' : '♡ Like'}{pending? '…':''}</button>
<div aria-live="polite" style={{color:'crimson'}}>{error}</div>
</div>
);
}
ReactDOM.createRoot(document.getElementById('try-optimistic')).render(<App />);
Syntax primer
- Apply the change on the client immediately; send the request in the background.
- On failure, roll back to previous state and notify the user.
Common pitfalls
- Race conditions when multiple updates occur—queue or tag operations to reconcile correctly.
Exercises
- Optimistically add a comment to a list; roll back on error.
Checks for Understanding
- Why stash previous state before an optimistic update?
- How do you handle multiple concurrent optimistic updates safely?
Show answers
- So you can roll back precisely if the server request fails.
- Tag updates with IDs or queue them; reconcile responses with the right update.