DEV Community

Jaligama Satyaveer
Jaligama Satyaveer

Posted on

React 19 : useOptimistic Hook

React 19 introduced several new features, including the useOptimistic hook.

useOptimistic help us in updating the UI when our async function is in progress.

Lets understand the use case of useOptimistic with an example

  1. When a user likes a post on Instagram.
  2. Client(Instagram app on user device) will make an API call to server for updating the number of likes. (asynchronous action)
  3. Once client receives the response from the server, UI will be updated accordingly with correct number of likes.

If the server is slow, there may be a delay in receiving the response and updating the UI, leading to a poor user experience.

The best way to enhance user experience

  1. User likes a post on Instagram.
  2. UI will display updated likes count without any delay.
  3. Client will make an API call to server. (asynchronous action)
  4. If API call is success, there will be no change in the UI (because we are already displaying updated likes count).
  5. If the API call is failed, like will be removed.

useOptimistic hook assists in managing likes while our asynchronous code (such as an API call in this case) is still underway.

API call Success

API call Failed

Code

import { HeartFilledIcon, HeartIcon } from "@radix-ui/react-icons";
import { Box, Strong, Text } from "@radix-ui/themes";
import { useOptimistic, useState, useTransition } from "react";

const UseOptimisticExample = () => {
  const [likes, setLikes] = useState(100);
  const [isPostLiked, setIsPostLiked] = useState(false);
  const [optimisticData, setOptimisticData] = useOptimistic(
    { likes, isPostLiked },
    (currentState, newLikes) => {
      return { likes: currentState.likes + newLikes, isPostLiked: true };
    }
  );
  const [, startTransition] = useTransition();

  const onLikeClick = () => {
    startTransition(async () => {
      setOptimisticData(1);
      //   Simulating API call
      await new Promise((resolve, reject) => {
        console.log("Request sent to server");
        setTimeout(() => {
          resolve(likes + 1); // To simulate API call success
          //   reject("API call failed"); // To simulate API call failure
        }, 8000);
      })
        .then((newLikes) => {
          console.log("API call success");
          setLikes(newLikes);
          setIsPostLiked(true);
        })
        .catch((error) => {
          console.error(error);
        });
    });
  };

  return (
    <Box py="1" px="2">
      {optimisticData.isPostLiked ? (
        <HeartFilledIcon
          color="red"
          style={{ height: "50px", width: "50px", cursor: "pointer" }}
          onClick={onLikeClick}
        />
      ) : (
        <HeartIcon
          style={{ height: "50px", width: "50px", cursor: "pointer" }}
          onClick={onLikeClick}
        />
      )}
      <br></br>
      <Text>
        <Strong>{optimisticData.likes} Likes</Strong>
      </Text>
    </Box>
  );
};

export default UseOptimisticExample;

Enter fullscreen mode Exit fullscreen mode

Top comments (0)