在使用React的useOptimistic钩子时,我得到了一个奇怪的行为。
运行:
“next”:“^14.0.4”与应用程序路由器。
当我点击按钮时,我立即得到2个控制台日志输出。
在第一个日志中,我可以看到乐观的结果:
{
"__typename": "GuideBlocksFormWebsite",
"id": "1",
"value": true,
"pending": true
}
字符串
然后在它恢复到第二个日志中所示的init状态后立即执行(不是所需的状态,因为值应该更新为true):
{
"__typename": "GuideBlocksFormWebsite",
"id": "1",
"value": false
}
型
SSR页面:
import { cookies } from 'next/headers'
import { createClient } from '@/utils/supabase/server'
import { Form } from './Form'
export const dynamic = 'force-dynamic'
const SSRPage = async () => {
const cookieStore = cookies()
const supabase = createClient(cookieStore)
const { data: form } = await supabase.from('forms_progress').select()
return (
<>
<Form initFormData={form} />
</>
)
}
export default SSRPage
型
initFormData看起来像这样:
form: [
{
id: '97b1672d-b119-473e-958c-8d1c0902fc09',
'mrkoll.se': false,
'eniro.se': false,
'merinfo.se': false,
'hitta.se': false,
'ratsit.se': false,
is_completed: false,
created_at: '2023-12-05T23:26:54.592581+00:00',
updated_at: '2023-12-05T23:26:54.592581+00:00',
'birthday.se': false
}
]
型
形式:
'use client'
import { useOptimistic, useState } from 'react'
import TickButton from './TickButton'
const keysToRender = ['mrkoll.se', 'eniro.se', 'merinfo.se', 'hitta.se', 'ratsit.se', 'birthday.se']
export const Form = ({ initFormData }) => {
const [form, setForm] = useState(initFormData[0])
const [optimisticTick, addOptimisticTick] = useOptimistic(form, (state, newValue) => {
return {
...state,
[newValue.key]: newValue.value,
}
})
const renderButtons = () => {
return keysToRender.map((key) => (
<TickButton
key={key}
id={key}
value={optimisticTick[key]}
addOptimisticTick={addOptimisticTick}
/>
))
}
return <>{optimisticTick && renderButtons()}</>
}
型
TickButton:
'use client'
import { useTransition } from 'react'
import useGuideForm from '@/app/hooks/useGuideForm'
import { useRouter } from 'next/navigation'
const TickButton = ({ id, value, addOptimisticTick }) => {
const { updateFormsProgress } = useGuideForm()
const [, startTransition] = useTransition()
const router = useRouter()
const handleOnClick = async () => {
startTransition(() => {
addOptimisticTick({ key: id, value: true, pending: true })
})
await updateFormsProgress({
[id]: true,
})
router.refresh()
}
return (
<button type="button" onClick={handleOnClick} disabled={value === true}>
{value ? 'Ready' : 'Confirm'}
</button>
)
}
export default TickButton
型
updateFormsProgress:
const updateFormsProgress = async (data: unknown) => {
try {
if (user) {
const { error } = await supabase
.from('forms_progress')
.update(data)
.eq('id', user?.id as string)
if (error) {
throw new Error(error.message)
}
}
} catch (error) {
captureException(error)
}
}
型
在这里播放的视频的行为:video
流程:
- Button的值为false,则在SSR期间获取数据,并将其作为init值传递给useOptimistic钩子。
- 按钮,乐观值 Flink 。
- 按钮 Flink 后返回假值。
- 按钮,则value被正确设置为true。
你对这里发生的事有什么线索吗?
3条答案
按热度按时间9gm1akwq1#
我在尝试实现useOptimistic钩子时遇到了类似的问题,而没有求助于服务器操作,revalidateTag和'no-cache'。虽然我不能确定为什么你的代码没有按预期运行,但它似乎应该。我不确定它是否可能是某种缓存问题。
然而,可能的解决办法可能涉及以下步骤:
1.实现服务器操作:
字符串
1.修改onClick处理程序:
型
1.在SSR页面上执行fetch调用:
型
此外,创建一个API端点(例如,API/form-progress)非常重要,该端点用于从数据库表中获取(GET)和变更(POST)数据。
umuewwlo2#
你需要确保你更新的是传入useOptimistic钩子的原始状态,而不仅仅是调用addOptimisticTick函数。
我认为react正在等待原始状态(Tick)更新,因为这就是为什么你想调用useOptimistic,但是原始状态没有更新,所以它停止使用乐观值并恢复到旧状态。
因此,您需要为传递到组件中的prop调用更新状态函数,useOptimistic不能替代该prop值
字符串
ddrv8njm3#
尝试删除你的Router OnClick函数中的router.refresh()调用。我认为这个调用可能会导致组件重新呈现,并且由于数据是在SSR期间获取的,并作为初始值传递给useOptimistic钩子,因此状态可能会重置为初始值。
试着这样做:
字符串