When users click a "Like" button or post a message, waiting 1-2 seconds for a server response makes applications feel slow. Optimistic UI updates show the expected success state immediately. If the server request fails, React automatically rolls back to the previous true state. React 19's `useOptimistic` hook handles this pattern out of the box!
1. `useOptimistic` Hook Syntax
import { useOptimistic } from 'react';
const [optimisticState, addOptimistic] = useOptimistic(
passthroughState,
// updateFn(currentState, optimisticValue) => newOptimisticState
(currentState, optimisticValue) => [...]
);
const [optimisticState, addOptimistic] = useOptimistic(
passthroughState,
// updateFn(currentState, optimisticValue) => newOptimisticState
(currentState, optimisticValue) => [...]
);
2. Complete Live Code Example: Instant Message Chat Feed
import React, { useState, useOptimistic } from 'react';
export default function Thread({ messages, sendMessageAction }) {
// 1. Define optimistic state linked to actual messages prop
const [optimisticMessages, addOptimisticMessage] = useOptimistic(
messages,
(currentMessages, newText) => [
...currentMessages,
{ text: newText, sending: true, id: Date.now() }
]
);
async function formAction(formData) {
const text = formData.get("message");
// 2. Instantly render optimistic message before server call
addOptimisticMessage(text);
// 3. Execute actual async server action
await sendMessageAction(text);
}
return (
<div className="p-4 border rounded">
<h4>Live Chat Feed</h4>
<ul className="list-group mb-3">
{optimisticMessages.map((msg, index) => (
<li key={index} className="list-group-item d-flex justify-content-between align-items-center">
{msg.text}
{msg.sending && <span className="badge bg-secondary">Sending...</span>}
</li>
))}
</ul>
<form action={formAction} className="d-flex gap-2">
<input type="text" name="message" placeholder="Type a message..." className="form-control" required />
<button type="submit" className="btn btn-warning">Send</button>
</form>
</div>
);
}
export default function Thread({ messages, sendMessageAction }) {
// 1. Define optimistic state linked to actual messages prop
const [optimisticMessages, addOptimisticMessage] = useOptimistic(
messages,
(currentMessages, newText) => [
...currentMessages,
{ text: newText, sending: true, id: Date.now() }
]
);
async function formAction(formData) {
const text = formData.get("message");
// 2. Instantly render optimistic message before server call
addOptimisticMessage(text);
// 3. Execute actual async server action
await sendMessageAction(text);
}
return (
<div className="p-4 border rounded">
<h4>Live Chat Feed</h4>
<ul className="list-group mb-3">
{optimisticMessages.map((msg, index) => (
<li key={index} className="list-group-item d-flex justify-content-between align-items-center">
{msg.text}
{msg.sending && <span className="badge bg-secondary">Sending...</span>}
</li>
))}
</ul>
<form action={formAction} className="d-flex gap-2">
<input type="text" name="message" placeholder="Type a message..." className="form-control" required />
<button type="submit" className="btn btn-warning">Send</button>
</form>
</div>
);
}
Build High Performance Apps with Telugu IT Tutorials
Learn React 19's optimistic state updates, server components, and Next.js App Router in our structured online cohorts. Explore Courses →