useOptimistic - example needed - codesandbox / stackblitz / github

I need to change data immediately without waiting for response from server - https://www.youtube.com/watch?v=wg3xQogkZDA&ab_channel=SonnySangha If you did this with useOptimistic or react-query - please send me like to example Also I tried to do it and got this error TypeError: (0 , react__WEBPACK_IMPORTED_MODULE_1__.experimental_useOptimistic) is not a function or its return value is not iterable To reproduce: 1. pnpm create-next-app@latest 2. paste this in page.tsx
"use client"

import { experimental_useOptimistic as useOptimistic } from "react"

export default function Home() {
let testNumber = 99
const [optimisticTest, optimisticTestFunction] = useOptimistic(
testNumber,
(state, amount: number) => state + Number(amount),
)
async function updateNumber(amount: number) {
optimisticTestFunction(amount)
}
return (
<div>
{optimisticTest}
<button onClick={() => updateNumber(-1)}>optimistic test</button>
<button onClick={() => updateNumber(+1)}>optimistic test</button>
</div>
)
}
"use client"

import { experimental_useOptimistic as useOptimistic } from "react"

export default function Home() {
let testNumber = 99
const [optimisticTest, optimisticTestFunction] = useOptimistic(
testNumber,
(state, amount: number) => state + Number(amount),
)
async function updateNumber(amount: number) {
optimisticTestFunction(amount)
}
return (
<div>
{optimisticTest}
<button onClick={() => updateNumber(-1)}>optimistic test</button>
<button onClick={() => updateNumber(+1)}>optimistic test</button>
</div>
)
}
Sonny Sangha
YouTube
Learn the useOptimistic Hook in 19 minutes (Next.js 13 For Beginners)
🚨 Join my course Zero to Full Stack Hero: https://www.papareact.com/course The useOptimistic hook provides a way to implement OPTIMISTIC updates. These Optimistic updates enhance the user experience by making the app appear more responsive to the user by displaying instant results on the front end. 🔴 LOOKING FOR THE CODE FROM THE BUILDS? 🛠️ ht...
1 Reply
Nikita
Nikita9mo ago
now I come up with this logic
const queryClient = useQueryClient()
const supabase = createClientComponentClient<Database>()

const {
mutate: updateTask,
isPending,
context,
} = useMutation({
mutationFn: async () =>
await supabase
.from("products")
.update({ on_stock: (on_stock += 1) })
.eq("id", "123"),
onMutate: async () => {
await queryClient.cancelQueries({ queryKey: ["userToDos"] })
const previousState: IProduct[] | undefined = queryClient.getQueryData(["userToDos"])
if (previousState) {
const updatedState = previousState
updatedState[0].on_stock += 1
console.log(31, "updatedState - ", updatedState)
queryClient.setQueryData(["userToDos"], updatedState)
return { updatedState }
}
},
onSuccess: () => {
toast({ title: "success", description: "task updated" })
},
onError: () => {
queryClient.setQueryData(["userToDos"], () => context?.updatedState)
toast({ title: "error", description: "error occured", variant: "destructive" })
},
onSettled: () => {
toast({ title: "onSettled", description: "onSettled description" })
},
})
//return
<CardDescription>{context?.updatedState[0].on_stock ?? on_stock}</CardDescription>
const queryClient = useQueryClient()
const supabase = createClientComponentClient<Database>()

const {
mutate: updateTask,
isPending,
context,
} = useMutation({
mutationFn: async () =>
await supabase
.from("products")
.update({ on_stock: (on_stock += 1) })
.eq("id", "123"),
onMutate: async () => {
await queryClient.cancelQueries({ queryKey: ["userToDos"] })
const previousState: IProduct[] | undefined = queryClient.getQueryData(["userToDos"])
if (previousState) {
const updatedState = previousState
updatedState[0].on_stock += 1
console.log(31, "updatedState - ", updatedState)
queryClient.setQueryData(["userToDos"], updatedState)
return { updatedState }
}
},
onSuccess: () => {
toast({ title: "success", description: "task updated" })
},
onError: () => {
queryClient.setQueryData(["userToDos"], () => context?.updatedState)
toast({ title: "error", description: "error occured", variant: "destructive" })
},
onSettled: () => {
toast({ title: "onSettled", description: "onSettled description" })
},
})
//return
<CardDescription>{context?.updatedState[0].on_stock ?? on_stock}</CardDescription>
But it works for like / unlike If I press button to update on_stock muiltiple times it change UI from 3 to 10 (for example) but when first query will success it change UI back from 3 to 4 If somebody know how to fix it - let me know - any updates with react-query how to do it would be nice I think its react-query issue and I found temp solution for its - its create state (but in this case I may don't use react-query for this and make it like this guy - https://www.youtube.com/watch?v=MC6D4vylKTc&t=4893s If you want you may vote up or comment or react somehow - https://github.com/TanStack/query/issues/6179
//create state to make next query based on optimistically updated previous one - https://github.com/TanStack/query/issues/6179
const [onStock, setOnStock] = useState(on_stock)

const {
mutate: updateTask,
isPending,
context,
} = useMutation({
mutationFn: async () => await supabase.from("products").update({ on_stock: onStock }).eq("id", "123"),
onMutate: async () => {
await queryClient.cancelQueries({ queryKey: ["userToDos"] })
const previousState: IProduct[] | undefined = queryClient.getQueryData(["userToDos"])
if (previousState) {
const updatedState = previousState
updatedState[0].on_stock += 1

console.log(31, "updatedState - ", updatedState)
setOnStock(updatedState[0].on_stock)
queryClient.setQueryData(["userToDos"], updatedState)
return { updatedState }
}
},
onSuccess: () => {
toast({ title: "success", description: "task updated" })
queryClient.invalidateQueries({ queryKey: ["userToDos"] })
},
onError: () => {
queryClient.setQueryData(["userToDos"], () => context?.updatedState)
toast({ title: "error", description: "error occured", variant: "destructive" })
},
onSettled: () => {
toast({ title: "onSettled", description: "onSettled description" })
queryClient.invalidateQueries({ queryKey: ["userToDos"] })
},
})

//return

<CardDescription>{context?.updatedState[0].on_stock ?? on_stock}</CardDescription>
//create state to make next query based on optimistically updated previous one - https://github.com/TanStack/query/issues/6179
const [onStock, setOnStock] = useState(on_stock)

const {
mutate: updateTask,
isPending,
context,
} = useMutation({
mutationFn: async () => await supabase.from("products").update({ on_stock: onStock }).eq("id", "123"),
onMutate: async () => {
await queryClient.cancelQueries({ queryKey: ["userToDos"] })
const previousState: IProduct[] | undefined = queryClient.getQueryData(["userToDos"])
if (previousState) {
const updatedState = previousState
updatedState[0].on_stock += 1

console.log(31, "updatedState - ", updatedState)
setOnStock(updatedState[0].on_stock)
queryClient.setQueryData(["userToDos"], updatedState)
return { updatedState }
}
},
onSuccess: () => {
toast({ title: "success", description: "task updated" })
queryClient.invalidateQueries({ queryKey: ["userToDos"] })
},
onError: () => {
queryClient.setQueryData(["userToDos"], () => context?.updatedState)
toast({ title: "error", description: "error occured", variant: "destructive" })
},
onSettled: () => {
toast({ title: "onSettled", description: "onSettled description" })
queryClient.invalidateQueries({ queryKey: ["userToDos"] })
},
})

//return

<CardDescription>{context?.updatedState[0].on_stock ?? on_stock}</CardDescription>