SuperAPI AI 工具集

sanity-form-component-suspense

编程与开发

查看项目

更新于 10-23 01:44

技能介绍

用途

本条目针对 Sanity Studio 中自定义表单组件挂起时出现的问题:Studio 为每个字段和每个数组项都放置了回退边界,因此单个挂起组件不会让整个表单变空白,但该回退是通用骨架,不知道被替换内容的尺寸,组件加载完成时表单会位移,Studio 会在控制台告警。修复方式始终在开发者自己的代码中:在挂起部分外围声明 Suspense,并提供与目标内容占用相同空间的回退。自声明的边界比 Studio 的更靠近挂起源,因此总会生效且不再告警。这包括自定义字段中围绕 props.renderDefault(props) 的边界,它也能覆盖该字段的输入框,适用于一个回退同时覆盖两者的场景,例如惰性加载且同时请求数据的输入框。

主要能力

  • 定位问题组件:告警会列出该字段或项声明的自定义组件(components.field、.input 或 .item)、路径、文档类型与 schema 类型,并记录组件本身;可在浏览器控制台点击组件打开源码。生产构建会压缩名称,此时用路径与文档类型定位。若 schema 类型未声明任何组件,告警以 “A form component” 开头,元凶通常是插件的 form.components。React DevTools 的 Suspense 标签页可显示实际挂起的组件。
  • 识别挂起源:常见为 React.lazy、use(promise)、App SDK 钩子(useDocumentProjection、useDocument、useQuery、useDocuments),或处于 suspense 模式的库(如 useSuspenseQuery)。
  • 拆分并包裹:若挂起部分尚未独立成组件,将其移入单独组件,只在自定义组件内用 <Suspense> 包裹该组件。将 props.renderDefault(props) 保持在边界之外,使内置输入框、字段或项在异步部分再次挂起时不会卸载(也不会在输入时丢失焦点)。
  • 预留空间:回退必须具有加载后 UI 的尺寸。附加型 UI(告警、预览、计数)应渲染在 renderDefault 之后,避免把后续内容下推,并让回退高度等于一行已加载内容;整体惰性加载的组件使用与组件高度一致的骨架,而非 null;数组项方面,列表是虚拟化的并会测量每行,因此项回退高度与已加载行不一致会导致下方行跳动,需匹配行高。
  • 避免对新文档挂起:新文档只有首次编辑创建后才存在,读取当前文档的 SDK 钩子会永远等待。应以 useFormValue(['_createdAt']) 作为条件,它在文档存在前未设置。
  • 保持 Promise 稳定:渲染期间、useState 或 useMemo 中创建的 Promise 在组件挂载挂起时会被丢弃,导致 use() 每次重试都拿到新 Promise 而永不 resolve。应使用 SDK 钩子、按输入键控的模块级缓存或数据库。

使用方式

按上述工作流排查与修复,示例代码展示了用 useFormValue 判断文档存在、将警告组件放入 Suspense 并以固定高度骨架占位的写法。

适用场景

适用于为 Sanity Studio 编写自定义表单组件、数组项组件或插件表单组件的开发者,尤其是组件使用了异步数据源且出现控制台告警或表单跳动的情况。

限制

资料未说明该技能在其他框架或非 Sanity Studio 环境中的适用性;若加载后 UI 高度可变,只能为最常见情况预留空间,并将可变部分放在输入框下方。