Nader's Daily Blog
Welcome to Every Developers favorite blog in the Devosphere

New product features | The latest in technology | The weekly debugging nightmares & more!

All you need to know about useOptimistic hook in Next js13

All you need to know about useOptimistic hook in Next js13

July 25, 2023

Nader Elmahdy

Nader Elmahdy

Take my knowledge and shove it up your brain...

A new experimental feature from Next js 13 that will greatly imporove your UX

Next js

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.

You might also like: