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.