首页/新闻资讯/正文详情

react-admin 实时订阅实战:深入掌握 `useSubscribeToRecord` 单记录事件订阅 Hook

发布时间:2026/9/21 3:28:00 来源:云帆数科 栏目:资讯中心
react-admin 实时订阅实战:深入掌握 `useSubscribeToRecord` 单记录事件订阅 Hook
react-admin 实时订阅实战深入掌握useSubscribeToRecord单记录事件订阅 Hook【免费下载链接】react-adminA frontend Framework for single-page applications on top of REST/GraphQL APIs, using TypeScript, React and Material Design项目地址: https://gitcode.com/gh_mirrors/re/react-adminuseSubscribeToRecord是 react-admin 企业版ra-realtime包中基于useSubscribe的特化 Hook用于订阅某个单一记录resource/[resource]/[recordId]topic上发布的实时事件。本文结合仓库中的官方文档与ra-realtime的底层机制完整讲解该 Hook 的用法、参数、回调语义以及它与useSubscribe、useSubscribeToRecordList、useGetOneLive的取舍帮助你在协同编辑、并发冲突提示、实时通知等场景中落地实时能力。背景ra-realtime的发布/订阅模型react-admin 为多人在线协作场景提供了实时Realtime能力允许多个用户并行工作、发布与订阅实时事件、在他人推送变更时自动刷新视图、向终端用户发送事件通知并通过锁机制防止同一资源被多人同时编辑。这些能力由react-admin/ra-realtime包提供属于 Enterprise Edition详见 docs/Realtime.md。其核心是一个发布/订阅pub/sub机制// 发布侧 const [publish] usePublish(); publish(topic, event); // 订阅侧 useSubscribe(topic, callback);ra-realtime在此基础上提供了一组高级 Hook 与组件useSubscribeToRecord就是其中之一与其并列的还有useSubscribe、useSubscribeCallback、useSubscribeToRecordList、usePublish完整列表见 docs/Realtime.md。在底层实时能力完全复用了 react-admin 的dataProvider适配器模式。要启用实时功能dataProvider需要实现三个新方法详见 docs/RealtimeDataProvider.mdsubscribe(topic, callback)unsubscribe(topic, callback)publish(topic, event)可选发布通常由服务端完成ra-realtime支持 Mercure、API Platform、Supabase、Socket.IO、Ably 等多种实时基础设施也可以基于本地变量手写自定义适配器仓库文档给出了基于内存数组的subscribe/unsubscribe/publish参考实现参见 docs/RealtimeDataProvider.md 的 Writing a Custom Adapter 一节。安装与前置条件ra-realtime是 React-Admin Enterprise Edition 的一部分托管在私有 npm registry 中需要订阅 Enterprise Edition 计划才能安装。按照 docs/Realtime.md 的说明安装npm install --save react-admin/ra-realtime # 或 yarn add react-admin/ra-realtime同时需要配置一个支持实时订阅的dataProvider具体要求见 docs/RealtimeDataProvider.md。基本用法订阅单记录事件useSubscribeToRecord与通用版useSubscribe的最大区别在于它只需要传一个回调函数资源名resource和记录 id 都会从当前上下文自动推断。回调会在resource/[resource]/[recordId]topic 上发布事件时被执行。以下示例实现了一个典型的并发编辑冲突提示组件当记录被他人更新收到edited事件时如果当前用户正在编辑表单isDirty就弹出一个对话框提醒冲突并允许用户选择保留自己的修改还是拉取对方的最新数据如果表单干净则直接refetch()刷新数据原文档 docs/useSubscribeToRecord.md 的完整示例import { useState } from react; import { useEditContext, useFormContext } from react-admin; import { Button, Dialog, DialogActions, DialogContent, DialogContentText, DialogTitle, } from mui/material; import { useSubscribeToRecord } from react-admin/ra-realtime; const WarnWhenUpdatedBySomeoneElse () { const [open, setOpen] useState(false); const [author, setAuthor] useStatestring | null(null); const handleClose () { setOpen(false); }; const { refetch } useEditContext(); const refresh () { refetch(); handleClose(); }; const { formState: { isDirty }, } useFormContext(); useSubscribeToRecord((event: Event) { if (event.type edited) { if (isDirty) { setOpen(true); setAuthor(event.payload.user); } else { refetch(); } } }); return ( Dialog open{open} onClose{handleClose} aria-labelledbyalert-dialog-title aria-describedbyalert-dialog-description DialogTitle idalert-dialog-title Post Updated by {author} /DialogTitle DialogContent DialogContentText idalert-dialog-description Your changes and their changes may conflict. What do you want to do? /DialogContentText /DialogContent DialogActions Button onClick{handleClose}Keep my changes/Button Button onClick{refresh} Get their changes (and lose mine) /Button /DialogActions /Dialog ); }; const PostEdit () ( Edit SimpleForm TextInput sourceid disabled / TextInput sourcetitle / TextInput sourcebody multiline / WarnWhenUpdatedBySomeoneElse / /SimpleForm /Edit );上下文推断与组件摆放位置useSubscribeToRecord会分别从ResourceContext和RecordContext读取当前的资源名与记录 id。上面的例子中当应用收到resource/books/123topic 上的事件时会触发通知——其中books来自ResourceContext123来自RecordContext。一个容易踩坑的细节是组件摆放位置Show、Edit等页面组件会创建RecordContext因此useSubscribeToRecord必须放在其子组件中才能读取到上下文而不能放在页面组件本身。原文档明确指出In the example above,Showcreates theRecordContext— thats why theuseSubscribeToRecordhook is used in its child component instead of in theBookShowcomponent.与useSubscribe一样当组件卸载时useSubscribeToRecord会自动从 topic 退订无需手动清理。显式指定 resource 与 recordId如果你不在ResourceContext/RecordContext的覆盖范围内例如在自定义页面、dashboard 或弹窗中可以显式传入资源名和记录 iduseSubscribeToRecord(event { /* ... */ }, posts, 123);这一行等价于订阅resource/posts/123topic。Tip如果你的目的仅仅是“保持记录数据最新”应优先使用useGetOneLive这个实时数据 Hook而不是自己处理事件后手动refetch前者会帮你完成订阅、事件处理与数据更新整个闭环见 docs/useGetOneLive.md。参数一览useSubscribeToRecord的签名如下useSubscribeToRecord(callback, resource?, recordId?, options?)PropRequiredTypeDefaultDescriptioncallbackRequiredfunction-The callback to execute when an event is received.resourceOptionalstring-The resource to subscribe to. Defaults to the resource in theResourceContext.recordIdOptionalstring-The record id to subscribe to. Defaults to the id of the record in theRecordContext.optionsOptionalobject-The subscription options.callback事件处理回调每当resource/[resource]/[recordId]topic 上有事件发布时第一个参数传入的回调会被调用事件对象作为其参数const [open, setOpen] useState(false); const [author, setAuthor] useStatestring | null(null); const { refetch } useEditContext(); const { formState: { isDirty }, } useFormContext(); useSubscribeToRecord((event: Event) { if (event.type edited) { if (isDirty) { setOpen(true); setAuthor(event.payload.user); } else { refetch(); } } });用useCallback记忆化回调订阅/退订的开销与回调引用的变化频率直接相关。每次渲染若传入新的内联函数都会触发一次订阅再退订。原文档建议使用useCallback记忆化回调把依赖项显式列出从而避免不必要的订阅/退订抖动const [open, setOpen] useState(false); const [author, setAuthor] useStatestring | null(null); const { refetch } useEditContext(); const { formState: { isDirty }, } useFormContext(); const handleEvent useCallback( (event: Event) { if (event.type edited) { if (isDirty) { setOpen(true); setAuthor(event.payload.user); } else { refetch(); } } }, [isDirty, refetch, setOpen, setAuthor] ); useSubscribeToRecord(handleEvent);回调的第二个参数unsubscribe与useSubscribe一致回调函数的第二个参数是一个unsubscribe函数。当需要“收到某个特定事件后就停止监听”时可以在回调内主动调用它——例如在记录被删除后立刻退订避免后续再处理该记录的任何事件useSubscribeToRecord((event: Event, unsubscribe) { if (event.type deleted) { // do something unsubscribe(); } if (event.type edited) { if (isDirty) { setOpen(true); setAuthor(event.payload.user); } else { refetch(); } } });options订阅行为控制options对象支持以下属性用于精细控制订阅/退订行为enabled是否订阅默认true。设为false可延迟订阅例如在异步拿到 record id 之前先不订阅once收到第一个事件后是否自动退订默认false。适合“等待某个一次性事件”如任务完成通知unsubscribeOnUnmount组件卸载时是否退订默认true。这些选项与useSubscribe完全相同更多细节与示例如once: true的一次性订阅演示参见 docs/useSubscribe.md。recordId覆盖订阅的记录 id默认情况下useSubscribeToRecord使用RecordContext中记录的 id 来构建订阅 topic。你也可以通过第三个参数显式覆盖// 将订阅 resource/posts/123 topic useSubscribeToRecord(event { /* ... */ }, posts, 123);一个值得注意的边界情况如果传入 null 作为 record idHook 不会订阅任何 topic。这在你尚未确定记录 id例如列表页等待选中行时非常有用可以安全地占位。resource覆盖订阅的资源名同理默认使用ResourceContext中的资源名来构建 topic可通过第二个参数显式覆盖// 将订阅 resource/posts/123 topic useSubscribeToRecord(event { /* ... */ }, posts, 123);另一个边界情况如果传入空字符串作为资源名Hook 同样不会订阅任何 topic。底层原理topic 与事件格式useSubscribeToRecord之所以能“猜”出订阅目标是因为ra-realtime对 CRUD 场景有一套约定的 topic 命名规范详见 docs/RealtimeDataProvider.md 的 Topic And Event Format 一节记录级 topicresource/[resource]/[id]—— 正是useSubscribeToRecord订阅的列表级 topicresource/[resource]—— 由useSubscribeToRecordList订阅见 docs/useSubscribeToRecordList.md。事件对象是带type和payload两个字段的普通 JavaScript 对象。对于 CRUD 操作ra-realtime约定使用created、updated、deleted三种事件类型例如记录更新时后端会同时向两个 topic 发布事件{ topic: resource/${resource}/id, event: { type: updated, payload: { ids: [id] }, }, } { topic: resource/${resource}, event: { type: updated, payload: { ids: [id] }, }, }记录创建时仅向列表 topic 发布created事件删除时则同时向记录 topic 与列表 topic 发布deleted事件事件格式详见 docs/RealtimeDataProvider.md 的 CRUD Events 一节。理解了这套约定你就能在自己的回调中针对event.type精准分流处理。与其他 Hook 的选型对比在ra-realtime的 Hook 家族中docs/Realtime.md 有完整列表useSubscribeToRecord的定位与取舍如下Hook订阅 topic适用场景useSubscribe任意 topic字符串通用消息、聊天频道、自定义 topic见 docs/useSubscribe.mduseSubscribeToRecordresource/[resource]/[id]关注单条记录的事件如并发编辑冲突提示useSubscribeToRecordListresource/[resource]关注整个资源列表的事件如有人新建/更新/删除了记录的通知与刷新见 docs/useSubscribeToRecordList.mduseGetOneLive内部封装只想让单条记录数据保持最新不需要自己处理事件选型建议如果只需要监听单个记录的变更并联动 UI弹窗、通知、局部刷新useSubscribeToRecord是最直接的选择如果数据只是“要最新”优先useGetOneLive如果是列表场景则看useSubscribeToRecordList或ListLiveUpdate组件。小结useSubscribeToRecord以最小的心智负担把“单记录实时事件监听”接入 react-admin无需手写 topic、无需手动订阅/退订仅凭ResourceContext与RecordContext即可完成全部推断配合useCallback记忆化、unsubscribe第二参数以及enabled/once/unsubscribeOnUnmount选项可以构建出从冲突提示、实时通知到一次性事件等待等丰富的协作型交互。掌握它的关键在于理解底层的 topic 约定resource/[resource]/[id]与 CRUD 事件格式created/updated/deleted两者共同构成了 react-admin 实时协作体系的基石。更多配套能力实时数据 Hook、锁机制、菜单徽标等可继续查阅 docs/Realtime.md 与 docs/RealtimeDataProvider.md。【免费下载链接】react-adminA frontend Framework for single-page applications on top of REST/GraphQL APIs, using TypeScript, React and Material Design项目地址: https://gitcode.com/gh_mirrors/re/react-admin创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关推荐

在 Vue 3 应用中接入 json-render DevTools:@json-render/devtools-vue 完整接入与源码解析
在 Vue 3 应用中接入 json-render DevTools:@json-render/devtools-vue 完整接入与源码解析

在 Vue 3 应用中接入 json-render DevTools:json-render/devtools-vue 完整接入与源码解析 【免费下载链接】json-render The Generative UI framework 项目地址: https://gitcode.com/GitHub_Trending/js/json-render json-render/devtools-vue 是 json-ren… · 2026/9/21 3:28:00

Etherpad 自更新子系统 Tier 3 深度解析:带宽限窗口的自动升级(Auto-Update with Grace Window)
Etherpad 自更新子系统 Tier 3 深度解析:带宽限窗口的自动升级(Auto-Update with Grace Window)

后端协同办公WebSocket前端富文本 【免费下载链接】etherpad Etherpad: A modern really-real-time collaborative document editor. 项目地址: https://gitcode.com/gh_mirrors/et/etherpad 点击查看 免费下载 Etherpad 内置的"自更新子系统"&#xff0… · 2026/9/21 3:28:00

lark-cli apps +plugin-list 命令完全指南:妙搭应用插件声明与安装状态核验
lark-cli apps +plugin-list 命令完全指南:妙搭应用插件声明与安装状态核验

CLIAI 技能 【免费下载链接】cli The official Lark/飞书 CLI tool, maintained by the larksuite team — built for humans and AI Agents. Covers core business domains including Messenger, Docs, Base, Sheets, Calendar, Mail, Tasks, Meetings, and more, with 200 co… · 2026/9/21 3:28:00

ARIS 工作流总览:从 idea 到 paper 的 13 条 pipeline 如何一次看全
ARIS 工作流总览:从 idea 到 paper 的 13 条 pipeline 如何一次看全

ARIS 工作流总览:从 idea 到 paper 的 13 条 pipeline 如何一次看全 【免费下载链接】Auto-claude-code-research-in-sleep ARIS ⚔️ (Auto-Research-In-Sleep) — Lightweight Markdown-only skills for autonomous ML research: cross-model review loops, idea … · 2026/9/21 4:06:05

南郊网站建设报价单背后的安全防线:3个实战案例揭秘
南郊网站建设报价单背后的安全防线:3个实战案例揭秘

南郊网站建设报价单背后的安全防线:3个实战案例揭秘 备案流程一头雾水?别急,南郊网站建设报价单里藏着比备案更深的坑。我见过太多老板盯着价格看,却忽略了“安全”二字。 上个月刚处理完一个 实战案例… · 2026/9/21 4:04:06

Roc 格式化器幂等性测试实战:从 issue 8851 快照看多行分发与字段访问的格式化处理
Roc 格式化器幂等性测试实战:从 issue 8851 快照看多行分发与字段访问的格式化处理

Roc 格式化器幂等性测试实战:从 issue 8851 快照看多行分发与字段访问的格式化处理 【免费下载链接】roc A fast, friendly, functional language. 项目地址: https://gitcode.com/GitHub_Trending/ro/roc 导读:本文以 Roc 编译器仓库中的快照测试… · 2026/9/21 4:04:05

TypePHP编译器API参考:程序化调用PHP AOT编译器的完整指南
TypePHP编译器API参考:程序化调用PHP AOT编译器的完整指南

TypePHP编译器API参考:程序化调用PHP AOT编译器的完整指南 【免费下载链接】typephp Compile PHP to Native Binaries 项目地址: https://gitcode.com/GitHub_Trending/ty/typephp TypePHP 是一款用 PHP 编写的原生 AOT 编译器(tpc)&a… · 2026/9/21 4:04:05

React Admin 实时数据提供者(Realtime Data Provider)接入完整指南:方法签名、内置适配器与自定义实现
React Admin 实时数据提供者(Realtime Data Provider)接入完整指南:方法签名、内置适配器与自定义实现

前端UI组件 【免费下载链接】react-admin A frontend Framework for single-page applications on top of REST/GraphQL APIs, using TypeScript, React and Material Design 项目地址: https://gitcode.com/gh_mirrors/re/react-admin 点击查看 免费下载 本指南系… · 2026/9/21 4:04:05

VitePress 默认主题 Layout 指南:深入理解 doc、page、home 与自定义布局
VitePress 默认主题 Layout 指南:深入理解 doc、page、home 与自定义布局

VitePress 默认主题 Layout 指南:深入理解 doc、page、home 与自定义布局 【免费下载链接】vitepress Vite & Vue powered static site generator. 项目地址: https://gitcode.com/gh_mirrors/vi/vitepress VitePress 通过 frontmatter 中的 layout 选项… · 2026/9/21 4:04:05

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化
Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡… · 2026/9/21 0:02:39

Word表格编号全攻略:从列表编号到题注交叉引用
Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技… · 2026/9/21 0:02:39

从第一个站到第二个站:独立开发者的静态网站选型与落地实践
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&… · 2026/9/20 0:00:41

Claude Code 按智谱AI指南装完,ANTHROPIC_BASE_URL 改走 TaoToken 兼容通道行不行
Claude Code 按智谱AI指南装完,ANTHROPIC_BASE_URL 改走 TaoToken 兼容通道行不行

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

agents-generator 决策矩阵全解析:从项目检测到 AGENTS.md 规则生成的 16 步判定流程
agents-generator 决策矩阵全解析:从项目检测到 AGENTS.md 规则生成的 16 步判定流程

agents-generator 决策矩阵全解析:从项目检测到 AGENTS.md 规则生成的 16 步判定流程 【免费下载链接】agentic-awesome-skills AAS Core is the local, agent-first control plane for complete catalog discovery, agent-owned selection, stack validation, and … · 2026/9/21 0:00:18

gin-vue-admin 前端工具函数全景指南:src/utils 复用规范与源码级解析
gin-vue-admin 前端工具函数全景指南:src/utils 复用规范与源码级解析

gin-vue-admin 前端工具函数全景指南:src/utils 复用规范与源码级解析 【免费下载链接】gin-vue-admin 🚀ViteVue3Gin拥有AI辅助的基础开发平台,企业级业务AI开发解决方案,内置mcp辅助服务,内置skills管理,… · 2026/9/21 0:00:18

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码