New product features | The latest in technology | The weekly debugging nightmares & more!
July 25, 2023
Take my knowledge and shove it up your brain...
When you're on Instagram and you like a post, you see the like button turns red immediately, but do you think the request gets served that quickly?
Probably not, but this is called optimistic behavior.
The application is optimistic that the request will succeed, and it shows you an immediate UI change until the request gets served, if it succeeds, nothing changes, and if an error occurs the UI will roll back the change.
Next js 13 has introduced a new hook called useOptimistic which does exactly what I talked about above.
To get started, import the hook from react
OptimisticDemo.tsx
1"use client"; 2import {experimental_useOptimistic as useOptimistic } from "react";
In this example, I have an e-commerce app, and I want when a user adds the product to favorites, the like button becomes red immediately.
To get an idea of how this works:
The default behavior (if I'm not being optimistic) is that the user would click the like button, wait for the request to end, and for the data to revalidate, then the like button would turn red.
The way useOptimistic
works is that you pass your initial value from the database, in my case it's an array of the user's favorite products, then we create a new copy of that array which is local to see immediate change effects.
OptimisticDemo
1function LikeButton({
2 favorites,
3}: {
4 favorites?: Array<{id:string}>;
5}) {
6 const [optimisticFav, modifyOptimisticFav] = useOptimistic(
7 favorites,
8 (state, newID) => {
9 if (state.some(({ id }) => id === newID)) {
10 return state.filter(({ id }) => id !== newID);
11 }
12 return [...state, { id: newID }];
13 }
14 );
In the above code, I pass the favorites
which is an array with the products' ids from my database.
The local copy of that array is the optimisticFav
and the modifyOptimisticFav
is the function that will mutate that copy.
The modifyOptimisticFav
will check if the id of that product exists in the array then it will remove it, if it doesn't, it will append it.
Now all I need to do is to check if the product ID exists in the local array, I show a red heart, if not, show a white heart.
OptimisticDemo
1 {optimisticFav.some(({ id }) => id === productID) ? (
2 <AiFillHeart size={35} fill="red" />
3 ) : (
4 <AiFillHeart size={30} fill="white" />
5 )}
Now the final step is when I click the like button, I want to modify both the local and the actual array in my database.
OptimisticDemo
1 <div
2 onClick={async () => {
3 // First modify the local array the wait for the server to respond
4 addOptimisticFav(productID);
5 await addToFavoritesAction(userId, { id: productID });
6 }}
7 className="w-24 rounded-md dark:bg-gray-200/70 bg-black/50 text-black font-bold h-10 items-center flex justify-center cursor-pointer"
8 >
9 {optimisticFav.some(({ id }) => id === productID) ? (
10 <AiFillHeart size={35} fill="red" />
11 ) : (
12 <AiFillHeart size={30} fill="white" />
13 )}
14 </div>
The addToFavoritesAction
is a server action I created, it checks if the product ID exists in the database, then it removes it, if not it adds it.
Next js 13 group routes is a game changer
This is a new feature in next js 13 that solves so many problems
Metadata guide in Next js 13
Next 13 introduced a new way to optimize your metadata, here's what you need to know
Next js 13 Route handlers explained
Forget the old api routes, this is the way
Next js 13 server actions introduction
Who needs api endpoints when we have server actions ?