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
- When a user likes a post on Instagram.
- Client(Instagram app on user device) will make an API call to server for updating the number of likes. (asynchronous action)
- 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
- User likes a post on Instagram.
- UI will display updated likes count without any delay.
- Client will make an API call to server. (asynchronous action)
- If API call is success, there will be no change in the UI (because we are already displaying updated likes count).
- 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;
Top comments (0)