EXAM-20260728-01:代码片段管理
本次选题依据
- 历史报告显示 Refine Hook 返回值与 mutation 解构掌握度为薄弱,本卷用
useList、useCreate、useUpdate、useDelete和useCustomMutation综合复测。 - 历史 JSX 题只有 15/40,存在字段遗漏、状态分支不完整和临时 UI 残留,本卷最后一题继续考查完整条件渲染与操作区组合。
- React Hook 依赖与稳定引用曾出现多处问题,本卷通过
useMemo、useCallback和useEffect再次检验。 - 表单状态同步和不可变数组重排属于新知识点,占本次主要主题的一半以内,用于建立能力基线。
文件顺序与数据流
moveCrateCodeSnippet.ts:不可变地调整片段顺序。CrateCodeSnippetDialog.tsx:维护新增/编辑表单与校验。CrateCodeSnippetsPanel.tsx:查询片段、组织 CRUD、重排和完整 UI。
数据流:moveCrateCodeSnippet → CrateCodeSnippetDialog → CrateCodeSnippetsPanel
本试卷仅包含前端代码,不包含后端、tRPC、Service、DAO 或数据库内容。
源文件
G:\Save\Grogramming\CodeForge\daedalus\apps\app\src\pages\CrateDetailPage\CrateCodeSnippetsPanel\moveCrateCodeSnippet.tsG:\Save\Grogramming\CodeForge\daedalus\apps\app\src\pages\CrateDetailPage\CrateCodeSnippetDialog\CrateCodeSnippetDialog.tsxG:\Save\Grogramming\CodeForge\daedalus\apps\app\src\pages\CrateDetailPage\CrateCodeSnippetsPanel\CrateCodeSnippetsPanel.tsx
第1题(文件 1/3):实现不可变的代码片段上下移动
- 上下文:面板把当前列表、目标下标和移动方向传入;返回值用于生成重排接口的
snippetIds。 - 目标:指定片段上下移动一格,并重新生成连续的
sortOrder。 - 已知:
snippets、index、direction: -1 | 1。 - 产出:有效移动返回新数组,无效移动返回原数组引用。
- 实现路线:计算目标下标并校验;复制数组后移动元素;按最终下标重建
sortOrder。 - 边界:首项上移、末项下移或目标元素不存在时,不修改输入,也不返回伪重排结果。
- 可用 API:
splice、map、数组展开语法。 - 自检:
[A,B,C]中 B 上移得到[B,A,C];A 上移保持原引用;输入数组未被修改。
第2题(文件 2/3):把编辑数据转换为表单默认值
- 上下文:
useForm初始化和弹窗重新打开时都会调用此函数。 - 目标:编辑时回填四个字段,新建时提供空字符串。
- 已知:
initialData可能是片段、null或undefined。 - 产出:完整
CrateCodeSnippetFormValues。 - 实现路线:分别读取
name、language、code、description;缺失值用空字符串兜底。 - 边界:不能把
undefined交给受控字段。 - 可用 API:可选链、空值合并。
- 自检:新建时四个字段均为字符串;编辑时完整回填。
第3题(文件 2/3):初始化表单并同步弹窗身份
- 上下文:父组件复用同一个 Dialog,在新建和不同编辑对象之间切换。
- 目标:使用 Zod 校验,并在打开或编辑对象改变时显示正确内容。
- 已知:
crateCodeSnippetFormSchema、getDefaultValues、initialData、open。 - 产出:
form以及负责reset的副作用。 - 实现路线:创建带泛型的表单;配置 resolver/defaultValues;仅在打开时按当前对象重置。
- 边界:从片段 A 切换到 B 时不能残留 A 的内容;关闭时无需重置。
- 可用 API:
useForm、zodResolver、form.reset、useEffect。 - 自检:新建字段为空;编辑字段来自当前片段;校验来自共享 Schema。
第4题(文件 2/3):桥接关闭与合法提交事件
- 上下文:Dialog 通过
onClose管理开关,通过onSubmit触发父级创建或更新。 - 目标:稳定通知关闭;只把校验通过的独立值对象交给父组件。
- 已知:
onClose、onSubmit、form.handleSubmit。 - 产出:
handleClose、handleSubmit。 - 实现路线:用
useCallback包装关闭;用form.handleSubmit包装提交;复制表单值后上报。 - 边界:校验失败不得调用父级提交;关闭回调不得在渲染时执行。
- 可用 API:
useCallback、form.handleSubmit、对象展开。 - 自检:取消只关闭;合法值只提交一次;非法值显示错误且不提交。
第5题(文件 2/3):渲染可校验的新增/编辑弹窗
- 上下文:完成的 Dialog 将由面板作为受控子组件使用。
- 目标:渲染四个字段、字段错误、服务端错误和提交状态。
- 已知:第3、4题产物、弹窗 Props、翻译函数和已导入 UI 组件。
- 产出:
Dialog → FormProvider → formJSX。 - 实现路线:绑定标题与关闭;注册四个字段;显示字段/服务端错误;提供取消和保存按钮。
- 边界:
htmlFor匹配字段 id;错误使用role="alert";代码框关闭拼写检查。 - 可用 API:
form.register、form.formState.errors、FormProvider、t。 - 自检:标题随模式切换;错误可被辅助技术感知;提交期间保存按钮禁用。
第6题(文件 3/3):建立列表查询与四类变更通道
- 上下文:容器通过
crateId获取片段,再把编辑值交给 Dialog。 - 目标:查询全部片段,派生稳定数组,并创建新增、更新、删除、重排 mutation。
- 已知:
crateId、资源名、Refine Hooks 和输入类型。 - 产出:
result、query、snippets和四种 mutation。 - 实现路线:按
crateId等值过滤;配置分页和启用条件;派生空数组回退;填写 mutation 泛型。 - 边界:加载状态来自
query;数据未返回时snippets不能是undefined。 - 可用 API:
useList、useMemo、useCreate、useUpdate、useDelete、useCustomMutation。 - 自检:空
crateId不请求;身份变化时过滤变化;空结果可安全读取和遍历。
第7题(文件 3/3):实现新增与编辑弹窗的数据流
- 上下文:Dialog 的合法表单值回到这里,
editingSnippet决定更新或新增。 - 目标:正确开关弹窗,并让同一入口完成 create/update 分流与错误反馈。
- 已知:
crateId、列表长度、两个 mutation、编辑状态和 setter。 - 产出:
handleAdd、handleEdit、handleCloseDialog、handleSubmit。 - 实现路线:新增/编辑时设置正确身份;关闭时复位;提交时先清错并分流;成功关闭、失败记录消息。
- 边界:编辑不能落入新增分支;新片段
sortOrder等于列表长度。 - 可用 API:
useCallback、crypto.randomUUID、mutation.mutate。 - 自检:新增无旧值;编辑保留原 id;失败时弹窗保持可见并展示错误。
第8题(文件 3/3):实现删除、重排与重试控制
- 上下文:卡片操作区调用这些回调;重排依赖第1题,删除依赖当前目标。
- 目标:安全删除、提交有效重排,并提供查询重试。
- 已知:
snippets、crateId、query、删除/重排 mutation 和重排工具。 - 产出:删除、移动、重试、打开确认、取消确认五个回调。
- 实现路线:删除目标判空;有效移动才提交 id 顺序;成功重排后 refetch;正确维护删除目标。
- 边界:越界移动不得发请求;无需阻塞等待 refetch。
- 可用 API:自定义 action、
map、query.refetch、useCallback。 - 自检:无效移动不请求;重排只发送 id;删除成功关闭确认框,失败显示错误。
第9题(文件 3/3):维护多项展开状态与异步派生状态
- 上下文:每张卡片独立展开代码,按钮还需要根据 mutation 状态禁用。
- 目标:不可变切换 Set 中的单个 id,并派生保存中、重排中状态。
- 已知:展开集合 setter 与三个 mutation 的
isPending。 - 产出:
handleToggleExpand、isSaving、isReordering。 - 实现路线:函数式更新;复制 Set;存在则删除,否则加入;组合 pending 标志。
- 边界:不得原地修改
current;保存状态覆盖创建和更新。 - 可用 API:
new Set(current)、has、add、delete、逻辑或。 - 自检:A、B 可同时展开;再次点击只收起目标;任一保存 mutation pending 时保存状态为真。
第10题(文件 3/3):组合完整的代码片段管理面板
- 上下文:前9题已提供查询、表单、CRUD、重排和展开能力。
- 目标:组合成可访问、可反馈、可操作的完整面板。
- 已知:全部状态与回调、两个 Dialog、Card/Badge/Button 和状态组件。
- 产出:标题区、错误提示、加载/错误/空/列表分支、两个弹窗。
- 实现路线:添加标题操作;按四种查询状态互斥渲染;卡片提供移动/编辑/删除/展开;展开显示代码;绑定弹窗 Props。
- 边界:图标按钮需要包含片段名称的
aria-label;装饰图标aria-hidden;列表 key 使用 id。 - 可用 API:
t、snippets.map、expandedSnippetIds.has、handleRetry。 - 自检:四种查询状态完整;边界与重排中按钮禁用;弹窗收到正确状态、错误和回调。
出题验证
- 3 个目标文件均由 Git 跟踪,出题前没有未提交改动。
- import、顶层公共类型和 export 签名已保持。
- 题号从 1 到 10 全局连续,每题均包含完整提示与自检。
git diff --check通过;未对故意挖空的答卷运行全量质量检查。- 题目归档不包含标准答案。