Optimistic updates are a powerful technique in modern web development, especially when it comes to improving the user experience. By updating the user interface optimistically, you can make the app feel more responsive and smooth, even when there’s a slight delay in the server response. In this article, we’ll explore how to implement optimistic updates using React.js’s new useOptimistic
hook in combination with Next.js 13.4's server action. We'll build a "Like" button functionality for tweets as an example to demonstrate this technique.
Prerequisites
Before we begin, make sure you have the following installed:
- Node.js (with npm or yarn) and a code editor of your choice.
- React.js and Next.js installed in your project.
Setting Up the Project
Assuming you already have a Next.js project set up with the necessary files, let’s proceed to implement the optimistic “Like” functionality.
Step 1: Server Action for Like
First, we need to implement the server action to handle the like functionality. In this example, we’ll use a simple database (db
) with two schema tables: tweets
and likes
. The likes
table will store the username and tweet_id for the likes. Below is the code for the server action located in ../actions/tweetLike.ts
:
// ../actions/tweetLike.ts
import { db } from "../db";
import { likes, tweets } from "../db/schema";
import { revalidatePath } from "next/cache";
import { eq } from "drizzle-orm";
import { currentUser } from "@clerk/nextjs";
export default async function tweetLike(tweet_id: string, Clikes: number) {
const user = await currentUser();
const tweetPost = await db
.update(tweets)
.set({ likes: Clikes + 1 })
.where(eq(tweets.id, BigInt(tweet_id)));
const liked = await db
.insert(likes)
.values({ tweet_id: BigInt(tweet_id), username: user?.username });
revalidatePath("/app");
}
Step 2: Creating the Optimistic “Like” Button
Now, let’s create the “Like” button component using React.js’s useOptimistic
hook. We'll name this component LikeButton
and place it in ../components/LikeButton.tsx
:
// ../components/LikeButton.tsx
import { experimental_useOptimistic as useOptimistic } from "react";
import tweetLike from "../actions/tweetLike";
export default function LikeButton({
likes,
tweet_id,
}: {
likes: number | null;
tweet_id: any;
}) {
const [optimisticLikes, addOptimisticLikes] = useOptimistic(
likes || 0, // Default to 0 likes if null
(state, l) => state + 1
);
return (
<div className="flex items-end space-x-3">
<svg
viewBox="0 0 24 24"
aria-hidden="true"
fill="#f43f5e"
onClick={async () => {
addOptimisticLikes(1); // Optimistically increment the like count
await tweetLike(tweet_id, optimisticLikes); // Call the server action
}}
className="r-1gfgf0w r-4qtqp9 r-yyyyoo r-z80fyv r-dnmrzs r-bnwqim r-1plcrui r-lrvibr r-19wmn03 text-blue-500 fill-blue-500 w-6 h-6 cursor-pointer"
>
{/* SVG code for Like button */}
</svg>
<span className="text-sm opacity-60">{Number(optimisticLikes)}</span>
</div>
);
}
In the LikeButton
component, we use the useOptimistic
hook to create the optimisticLikes
state variable, which holds the optimistic number of likes. The hook takes an initial value (likes
prop or 0) and an updater function that increments the state by 1.
When the user clicks the “Like” button, we call the addOptimisticLikes
function to optimistically increase the like count. Next, we call the tweetLike
server action, passing the tweet_id and the optimistic like count. The server action will handle the actual like process, and in the response, we'll get the updated like count.
Conclusion
In this article, we explored how to create optimistic updates in the UI using React.js’s new useOptimistic
hook and Next.js 13.4's server action. By implementing optimistic updates, we can enhance the user experience by making the app feel more responsive and smooth. In the example of a "Like" button for tweets, we showed how to increment the like count optimistically and update it on the server using the provided server action.
Optimistic updates can be used in various scenarios to provide a better user experience and reduce perceived latency in web applications. However, keep in mind that it’s essential to handle potential discrepancies between the optimistic UI and the server’s actual state. In some cases, you may need to handle errors or roll back optimistic updates if the server response indicates a failure.
By combining React.js’s new useOptimistic
hook with Next.js's server action, you can take advantage of these powerful features to create a seamless and responsive user interface in your web applications.