Suggest an editImprove this articleRefine the answer for “What is an "optimistic update"?”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)An **optimistic update** is an approach where **the UI updates immediately**, *before* the server has confirmed the data change. **Key point:** the application optimistically assumes the server operation will succeed and updates the interface instantly, so the user does not feel a delay.Shown above the full answer for quick recall.Answer (EN)Image## What an "optimistic update" is An **optimistic update** is an approach where **the UI updates** ***immediately***, *before* the server has confirmed the data change. > That is, the application **optimistically assumes** the server operation will succeed, > and updates the interface **instantly**, so the user does not feel a delay. --- ### Example without an optimistic update: ```javascript async function handleLike(postId) { await fetch(`/api/posts/${postId}/like`, { method: "POST" }); refetch(); // wait for the server's response, then update the UI } ``` Downsides: - The "like" button is clicked → but the UI does not change until the response arrives. - The user feels a **300-500 ms delay** (or more on a bad connection). - The app feels "sluggish". --- ### Example with an **optimistic update**: ```javascript const queryClient = useQueryClient(); async function handleLike(postId) { // 1. Update the UI locally right away queryClient.setQueryData(['post', postId], (old) => ({ ...old, likes: old.likes + 1, isLiked: true, })); try { // 2. Send the request to the server await fetch(`/api/posts/${postId}/like`, { method: 'POST' }); } catch (err) { // 3. If the server responds with an error, roll back the changes queryClient.invalidateQueries(['post', postId]); } } ``` The user sees the update **instantly**, even without a response from the server. Once the server confirms, everything is already in sync. If the server responds with an error, the data **rolls back** to the actual state. --- ## A visual scenario | Event | What the user sees | What happens in the code | | --- | --- | --- | | Clicked the "like" button | the like becomes active | `setQueryData()` updates the cache immediately | | The server receives the request | nothing changes in the UI | `fetch()` runs in the background | | The server responds 200 OK | everything stays as is | the cache remains current | | The server responds 500 | the like disappears | a rollback (`invalidateQueries` or rollback) | --- ## Why this matters ### 1. **Instant response** The user feels the app works "in real time", with no delay even on a slow network. ### 2. **Smooth UX** The interface reacts right away, without loader "flickers". Optimistic updates are especially important in interactive actions: - likes, - commenting, - voting, - changing a name, status, or an item's position in a list. ### 3. **Independence from the network** If the request fails, the local changes can be rolled back. The user does not lose context (they see that the action "got cancelled"). --- ## How it is implemented in practice ### 1. **React Query** ```javascript import { useMutation, useQueryClient } from '@tanstack/react-query'; function useLikePost() { const queryClient = useQueryClient(); return useMutation({ mutationFn: (postId) => fetch(`/api/posts/${postId}/like`, { method: 'POST' }), // 1. Optimistically update the cache onMutate: async (postId) => { await queryClient.cancelQueries(['post', postId]); const prevPost = queryClient.getQueryData(['post', postId]); queryClient.setQueryData(['post', postId], (old) => ({ ...old, likes: old.likes + 1, isLiked: true, })); // 2. Return data for a rollback return { prevPost }; }, // 3. On error, roll back onError: (err, postId, context) => { queryClient.setQueryData(['post', postId], context.prevPost); }, // 4. On success, update or invalidate onSettled: (postId) => { queryClient.invalidateQueries(['post', postId]); }, }); } ``` `onMutate` → local update `onError` → rollback `onSettled` → final update/validation --- ### 2. **SWR (Vercel)** ```javascript import useSWR, { mutate } from 'swr'; function likePost(postId) { // optimistically increase the like count mutate(`/api/posts/${postId}`, async (data) => { await fetch(`/api/posts/${postId}/like`, { method: 'POST' }); return { ...data, likes: data.likes + 1, isLiked: true }; }, { optimisticData: { ...data, likes: data.likes + 1, isLiked: true }, rollbackOnError: true }); } ``` --- ### 3. **Redux Toolkit Query** RTK Query also lets you temporarily update the cache locally: ```javascript const [updatePost] = useUpdatePostMutation(); updatePost(newData) .unwrap() .then(() => dispatch(api.util.invalidateTags(['Post']))) .catch(() => revertLocalState()); ``` --- ## 4. Typical use cases for optimistic updates | Action | What we update locally | | --- | --- | | Like | Increase the like counter | | Adding a comment | Add the comment to the list | | Deleting an item | Remove it from the UI before the server responds | | Editing a profile | Change the name/avatar locally | | Reordering | Rearrange the items locally | | Payment / order | Mark it "created" before server confirmation | --- ## Summary | What Optimistic Update does | Why it matters | | --- | --- | | Updates the UI **before** the server responds | instant response | | Improves UX and perceived speed | no "delay" during interaction | | Syncs up on success | the UI and server stay consistent | | Rolls back on error | reliable on an unstable network | | Cuts down the number of `loading` states | the interface feels "alive" | --- ### In short: > An **optimistic update** is a way to make the interface instantly responsive: > the UI updates right away, *optimistically assuming success*, > and if the server returns an error, React rolls back the changes.For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.