In the previous two articles, we explored fetching data in a client component In React using the use() hook during rendering and mutating data with server actions. To further enhance the user experience, we can also introduce optimistic updates.

Optimistic updates is a technique where the UI is updated immediately in response to a user action. This occurs before the server confirms that the action has been successfully processed. 

The useOptimistic hook

The useOptimistic hook improves user experience by providing instant UI feedback, making the app feel faster and more responsive. It also simplifies handling asynchronous server actions by updating the UI immediately and ensuring smooth transitions.

To expand on the previous example, we can implement it like this.

"use client";
import { useActionState, useOptimistic, use } from "react"; 
import { createComment } from "../actions/createComment";
import { useRouter } from "next/navigation";
export default function Comments({ getCommentsPromise }) {
  const initialComments = use(getCommentsPromise);
  const [optimisticComments, addOptimisticComment] = useOptimistic(
    initialComments,
    (prevComments, optimisticComment) => [...prevComments, optimisticComment]
  );
  const [, createCommentAction, isCreatingComment] =
    useActionState(createComment, null);
  const router = useRouter();
  return (
    <div>
      <h2>Existing Comments</h2>
      <ul>
        {optimisticComments.map((comment) => (
          <li key={comment.id}>
            <p>{comment.message}</p>
          </li>
        ))}
      </ul>
      <h2>Add a new comment</h2>
      <form
        action={async (formData) => {
          addOptimisticComment({ 
            id: Math.round(Math.random() * 100), 
            message: formData.get("message"),
          });
          await createCommentAction(formData);
          router.refresh();
        }}
      >
        <div>
          <label htmlFor="message">Message:</label>
          <textarea id="message" name="message" required />
        </div>
        <button type="submit" disabled={isCreatingComment}>
          {isCreatingComment ? "Submitting..." : "Submit"}
        </button>
      </form>
    </div>
  );
}

To summarise; useOptimistic initialises with both initialComments , which are fetched on render, and an updater function, which appends new comments to the current list. 

When a user submits a comment, addOptimisticComment adds it to the UI immediately, giving the comment a temporary id and displaying it as if it were already saved. This makes the app feel more responsive, the user sees their comment appear instantly while the form data is sent to the server in the background. 

Finally, the router.refresh() call ensures the route is refreshed, fetching the latest data from the server to ensure that the displayed comments are up-to-date with the server's state.

Also read: