Refine 中用 useUpdate 钩子更新记录:从实现 DataProvider.update 到乐观更新与查询失效机制

发布时间:2026/11/7 15:41:31

Refine 中用 useUpdate 钩子更新记录:从实现 DataProvider.update 到乐观更新与查询失效机制 Refine 中用 useUpdate 钩子更新记录从实现 DataProvider.update 到乐观更新与查询失效机制【免费下载链接】refineA React Framework for building internal tools, admin panels, dashboards B2B apps with unmatched flexibility.项目地址: https://gitcode.com/GitHub_Trending/re/refine本文基于 Refine 官方教程中“Updating a Record”一节完整演示如何在数据提供层实现update方法、如何用useUpdate钩子更新单条 API 记录并结合packages/core源码剖析该钩子背后的乐观更新、智能失效Smart Invalidations与可撤销undoable变更机制。读完本文你不仅能复刻教程中的完整操作还能理解useUpdate在 TanStack Query 之上封装了哪些自动化行为。一、更新记录的两步走update方法与useUpdate钩子Refine 的数据交互遵循“数据提供层 数据钩子”的分层模型。要更新一条记录需要完成两件事在 DataProvider 中实现update方法——这是所有更新操作的统一入口在组件中调用useUpdate钩子——它会最终路由到 DataProvider 的update方法。useUpdate钩子及全部数据钩子的源码位于 useUpdate.ts其 JSDoc 明确说明它是 “react-querysuseMutation的修改版专用于 update 变更”并以传入Refine的 DataProvider 的update方法作为变更函数mutation function。二、实现update方法update方法接受四个属性属性说明resource要更新的实体资源名id要更新的记录 IDvariables发送到 API 的数据对象meta传递给钩子的附加数据如筛选、分页等查询上下文Refine 自带的 fake APIhttps://api.fake-rest.refine.dev要求通过PATCH /products/:id端点更新记录。因此我们在>import type { DataProvider } from refinedev/core; const API_URL https://api.fake-rest.refine.dev; export const dataProvider: DataProvider { getOne: async ({ resource, id, meta }) { const response await fetch(${API_URL}/${resource}/${id}); if (response.status 200 || response.status 299) throw response; const data await response.json(); return { data }; }, update: async ({ resource, id, variables }) { const response await fetch(${API_URL}/${resource}/${id}, { method: PATCH, body: JSON.stringify(variables), headers: { Content-Type: application/json, }, }); if (response.status 200 || response.status 299) throw response; const data await response.json(); return { data }; }, getList: () { throw new Error(Not implemented); }, /* ... */ };从源码结构看DataProvider 接口中update是必选方法与可选的updateMany?、getMany?不同签名为update: TData extends BaseRecord BaseRecord, TVariables {}( params: UpdateParamsTVariables, ) PromiseUpdateResponseTData;即update返回PromiseUpdateResponseTData其中UpdateResponse定义为{ data?: TData }。这也解释了教程代码为什么统一用return { data }包裹响应体——这是钩子约定读取结果的方式。三、使用useUpdate钩子实现update方法后就可以调用useUpdate更新单条记录。教程中我们新建EditProduct组件先用useOne拉取待更新记录再用useUpdate发起更新src/pages/products/edit.tsximport { useOne, useUpdate } from refinedev/core; export const EditProduct () { const { result, query: { isLoading }, } useOne({ resource: products, id: 123 }); const { mutate, mutation: { isPending: isUpdating }, } useUpdate(); if (isLoading) { return divLoading.../div; } const updatePrice async () { await mutate({ resource: products, id: 123, values: { price: Math.floor(Math.random() * 100), }, }); }; return ( div divProduct name: {result?.name}/div divProduct price: ${result?.price}/div button onClick{updatePrice}Update Price/button /div ); };然后在src/App.tsx中把EditProduct挂到Refine /组件内import { Refine } from refinedev/core; import { dataProvider } from ./providers/data-provider; import { ShowProduct } from ./pages/products/show; import { EditProduct } from ./pages/products/edit; export default function App(): JSX.Element { return ( Refine dataProvider{dataProvider} {/* ShowProduct / */} EditProduct / /Refine ); }此时页面会显示产品名称与价格点击 “Update Price” 按钮后价格即被更新。useUpdate的入参类型UpdateParams中除教程用到的resource/id/values外还支持mutationMode、undoableTimeout、onCancel、meta、dataProviderName、invalidates、optimisticUpdateMap等选项这些将在下一节结合源码展开。四、源码深潜useUpdate到底做了什么useUpdate.ts 中useUpdate内部构建了一个 TanStack Query 的useMutation并分四个阶段工作4.1 mutationFn参数校验与 DataProvider 调用在 mutationFn 中id、values、resourceName三者缺一即抛出预定义错误missingIdError、missingValuesError、missingResourceError。随后钩子把values重命名为variables调用 DataProviderdataProvider(...).updateTData, TVariables({ resource: resource.name, id, variables: values, meta: combinedMeta, });注意resource会先经过select(resourceName)解析——这意味着传入identifier资源标识符而非nameAPI 资源名时也能正确路由到对应 DataProvider测试 useUpdate.spec.tsx 中专门有 “when passingidentifierinstead ofname” 的 describe 块验证这一点。4.2 onMutate默认开启的乐观更新这是教程没有展开、但源码里最核心的部分。在 onMutate 阶段先通过queryClient.getQueriesData快照保存该资源所有相关查询的当前数据previousQueries取消正在进行的请求cancelQueries只要 mutation 模式不是pessimistic就按optimisticUpdateMap配置把values直接合并进缓存——默认配置为{ list: true, many: true, detail: true }即列表查询list、多记录查询many、详情查询one全部即时更新if (optimisticUpdateMap.list) { queryClient.setQueriesData({ queryKey: resourceKeys.action(list)... }, (previous) { // 将 values 合并到 previous.data 中 id 匹配的记录上 }); }因此界面在 API 返回前就显示新值。optimisticUpdateMap的每一项都可以传自定义映射函数OptimisticUpdateMapType如(previous, values, id) 新数据也可以传false关闭对应通道的乐观更新——这些行为在 useUpdate.spec.tsx 的 “when passingoptimisticUpdateMap” 测试块中有完整断言。4.3 onSettled智能失效Smart Invalidations教程提示框中提到“用useUpdate更新价格后之前调用的useOne会自动失效”。源码依据就在 onSettledconst { invalidates invalidatesFromProps ?? [list, many, detail] } variables; invalidateStore({ resource: identifier, dataProviderName: ..., invalidates, id, });无论成功或失败钩子都会失效该资源下list/many/detail三类查询可通过invalidates参数收窄范围触发 TanStack Query 重新拉取从而保证屏幕数据始终是最新的——这正是教程中“Smart Invalidations”提示的底层实现。4.4 onSuccess 与 onError发布事件、审计日志与回滚onSuccessL467-L563除了弹出默认的 “Successfully updated xxx” 成功通知还会通过publish向resources/{resource}频道发布updated实时事件供 LiveProvider 使用并调用log.mutate记录变更前后的数据供审计日志使用。onSuccess里还会从旧缓存中抽取被修改字段的原值作为previousData一并写入日志。onErrorL564-L613若存在onMutate保存的previousQueries快照会把每个查询的数据逐条恢复为变更前状态若是mutationCancelledundoable 模式被用户取消则静默处理否则弹出 “Error when updating xxx (status code: ...)” 错误通知。测试用例 “should work with optimistic update” 完整印证了这条链路先用mutationMode: optimistic发起更新断言useOne/useList/useMany的结果立刻变为新标题再让 API 以 500ms 延迟后报错断言三个查询的结果回滚为初始标题见 useUpdate.spec.tsx。五、三种变更模式Mutation Mode源码中mutationMode支持三种取值缺省时从Refine的 mutation 上下文useMutationMode继承模式行为optimistic默认请求发出前立即用新值更新缓存失败后回滚pessimistic等待 API 成功响应后才失效并重取缓存不会被提前修改undoable不立即请求而是把变更加入可撤销队列在undoableTimeout毫秒内用户可取消onCancel拿到cancelMutation函数超时后自动执行真实请求undoable的实现见 mutationFn 中的 updatePromise它把真实请求包装成doMutation连同cancelMutation一起通过notificationDispatch分发给通知层从而在 UI 上呈现带撤销按钮的提示。测试文件中对应 “should work with undoable update” 用例。六、钩子返回值与错误边界useUpdate最终返回L655-L660return { mutation: mutationResult, // 完整的 react-query useMutation 结果isPending/isError/isSuccess... mutate: handleMutation, // variables 参数可省略的 mutate mutateAsync: handleMutateAsync, overtime: { elapsedTime }, // 加载超时计时useLoadingOvertime };mutate/mutateAsync被包装了一层使得resource/id/values既可以在钩子入参中给也可以在mutate()调用时给“with props” 与 “with params” 两种用法在 useUpdate.spec.tsx 中各有一整组 describe 块验证overtime.elapsedTime配合overtimeOptions可用于实现“加载超过 N 秒就提醒用户”的体验缺失参数时抛出的错误信息如 “[useUpdate]:idis not defined but is required in edit and clone actions”对排查“为什么我的 update 没生效”非常有用注意id: 0、id: 等合法值不会误报——测试 “should not throw error when id 专门覆盖了这一边界。七、小结这篇教程展示了 Refine 更新记录的完整闭环DataProvider 的update方法负责把resource/id/variables/meta翻译成一次PATCH请求useUpdate钩子则在其上叠加了参数校验、乐观更新、失败回滚、跨查询智能失效、实时事件发布与审计日志记录。理解 packages/core/src/hooks/data/useUpdate.ts 与 packages/core/src/hooks/data/useUpdate.spec.tsx 这两份文件后再遇到useList、useCreate、useDelete等兄弟钩子同目录 hooks/data你会看到几乎一致的架构mutationFnonMutate乐观更新 onSettled失效 onSuccess/onError副作用只是查询键与数据形状不同。【免费下载链接】refineA React Framework for building internal tools, admin panels, dashboards B2B apps with unmatched flexibility.项目地址: https://gitcode.com/GitHub_Trending/re/refine创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
延伸阅读

更多相关文章

2026/11/7 15:41:31

CogVideoX文生视频完整教程:单卡5秒出片

CogVideoX文生视频完整教程:单卡5秒出片 【免费下载链接】CogVideo text and image to video generation: CogVideoX (2024) and CogVideo (ICLR 2023) 项目地址: https://gitcode.com/GitHub_Trending/co/CogVideo python inference/cli_demo.py --prompt &…

2026/11/7 15:39:52

曹县电工证在哪里考保姆级教程:电工证没到手,工作机会就没了

曹县电工证在哪里考保姆级教程:电工证没到手,工作机会就没了 你缺一张电工证,别人就多一份机会。在曹县,找电工相关的工作,电工证几乎是 硬性门槛 ,没有它,连面试资格都没有。尤其是现在企业招聘越来越规范,特种作业证成了“门槛证”,没有它,…

2026/11/7 15:39:52

曹县电工证在哪里考值不值得考

曹县电工证在哪里考值不值得考 之前考的证在外省能不能转过来?这是很多电工朋友心头的疑问。特别是在曹县,有些人在外地打工多年,考了电工证,回来之后却发现手续繁琐,甚至不知从何下手。 值不值得考…

2026/11/7 15:39:52

周先华高压电工证怎么报名 实操考试心里没底怕挂科?这3步教你搞定

周先华高压电工证怎么报名 实操考试心里没底怕挂科?这3步教你搞定 实操考试心里没底怕挂科?你不是一个人。特别是像我们平顶山市从事市政公用工程的朋友,高压电工证不仅是从业门槛,更是日常操作的“安全锁”。很多人在报名时对流程不清楚,对考试内容不…

2026/11/7 15:39:52

建筑特种工和技术工报名怕被坑?真实经历告诉你怎么避坑

建筑特种工和技术工报名怕被坑?真实经历告诉你怎么避坑 不知道去哪报名怕被中介坑,是很多初次报考建筑特种工和技术工的新人最真实的困扰。我自己当初也是在朋友介绍下,稀里糊涂地交了钱,结果证书还没拿到,钱就打水漂了。今天我就从一个过来人的角度,把…

2026/11/7 15:39:52

电工证能在异地年检吗 30天拿证攻略全解析

电工证能在异地年检吗 30天拿证攻略全解析 急需特种作业证才能上岗找工作,电工证作为高需求证书之一,不仅关系到能否入职,还直接决定了薪资水平和发展空间。不少朋友问: 电工证能在异地年检吗 ?更有人担心 多久拿证…

2026/11/7 15:34:51

证书过期了不知道怎么复审延期?硬件施工电工证上岗必备全流程详解

证书过期了不知道怎么复审延期?硬件施工电工证上岗必备全流程详解 证书过期了不知道怎么复审延期?你不是一个人,很多郑州市政公用工程从业者都遇到过这个问题。别急,下面一步步告诉你怎么搞定硬件施工电工证的复审和延期,确保你随时“上岗必备”,不掉链…

2026/11/7 14:54:47

面向复杂光照与角度的宠物面部识别鲁棒性增强策略

在智慧养宠时代,基于视觉的宠物身份识别技术正逐步从实验室走向家庭应用。然而,与配合度高的人类不同,宠物是典型的“非合作生物识别对象”——它们不会主动配合摄像头调整姿态,更无法控制光照环境。实际应用中,我们常…

2026/11/7 14:50:12

SSM电子书店源码全解析:结构、原理、部署与排错实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/11/7 0:03:08

郑州报考避坑指南:电工证和钳工证怎么选?实操考试心里没底怕挂科

郑州报考避坑指南:电工证和钳工证怎么选?实操考试心里没底怕挂科 实操考试心里没底怕挂科?你不是一个人。特别是在郑州这样的城市,很多施工企业负责人和一线作业人员在报考电工证和钳工证时都面临着同样的困惑。到底该考哪个证?哪个更适合自己?哪个证书…

2026/11/7 0:03:08

广西电工证办理流程全解析:外省证怎么转?在哪考最靠谱?

广西电工证办理流程全解析:外省证怎么转?在哪考最靠谱? 之前考的证在外省能不能转过来?这个问题我遇到太多了,今天就拿广西电工证办理流程来具体说说,别再走弯路了。广西电工证的报考、复审、继续教育这些环节,如果你不了解,真的会吃大亏,尤其对于从…

2026/11/7 0:03:08

电气电工证都有哪些保姆级教程

电气电工证都有哪些保姆级教程 你是不是正愁不知道去哪报名,怕被中介坑?别急,这篇保姆级教程专为河南初次报考人员准备,帮你搞清楚 电气电工证都有哪些 ,以及如何避开那些坑。 电气电工证都有哪些?别被五花八门的证书搞懵了…

2026/11/7 14:54:47

面向复杂光照与角度的宠物面部识别鲁棒性增强策略

在智慧养宠时代,基于视觉的宠物身份识别技术正逐步从实验室走向家庭应用。然而,与配合度高的人类不同,宠物是典型的“非合作生物识别对象”——它们不会主动配合摄像头调整姿态,更无法控制光照环境。实际应用中,我们常…

2026/11/7 14:50:12

SSM电子书店源码全解析:结构、原理、部署与排错实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑