用途
该技能负责前端代码的放置、React、TanStack Query、状态与 UI 约定。类型、schema、模块、注释和通用测试交由 typescript-standards 处理;添加服务端函数(含 stub)时使用 cloudflare-backend。
主要能力
框架约定
使用 TanStack Start,不使用 Next.js。采用传统 SSR + hydration,无 RSC,无 'use client'。仅服务端代码通过 createServerFn() 实现,位于 src/server/entrypoints/functions/。Loader 是同构的,在服务端和客户端都会运行;密钥与数据库访问通过服务端函数进行。
架构(Feature-Sliced Design)
依赖方向为:Route → Page → Feature → Entity → Shared。导入指向更低层。页面在无需可复用 feature 时可组合 shared UI 与 entities。
目录结构(apps/<app>/src/):routes/(薄适配层,委托给 pages/)、pages/(编排器)、entities/(业务概念:类型、工厂、纯派生)、features/(用户操作与可复用工作流)、ui/(应用专属展示与样式)、lib/(客户端、router、共享 hooks)、server/(后端部分)。
层规则:Route 是薄适配器;Page 组合 feature,无内联服务;Feature 拥有操作工作流、组件与 hooks;Entity 拥有可复用业务数据及其查询/变更工厂;UI 组件是纯的,无 API 调用、无业务逻辑、无 feature 导入。Entity 切片不得导入同级 entity 切片;Feature 切片不得导入同级 feature 切片。应用页面保持在 100 行以内。
组件架构(Fowler 分层)
Components:薄 JSX,仅 props/handlers,<100 行(目标 50)。Hooks:状态/副作用,两个以上查询合并为领域对象,或展示模型。Models:框架无关的业务逻辑,零 React 依赖。Services/queries:数据获取与 API↔领域转换。
展示模型:路由读取 hook 并将结果向下传递。将查询状态映射为 props 属于拥有该屏幕视图模型的 hook。
数据层——查询与变更工厂
每个 entity 暴露可复用的 queryOptions、infiniteQueryOptions 和 mutationOptions 构建器。工厂拥有 key、类型化请求、领域转换与缓存副作用。消费者 hook 拥有屏幕状态与操作顺序。
查询 key 包含 queryFn 读取的每个输入。层级:['products'] → ['products', 'list'] → ['products', 'list', filters] → ['products', 'detail', input]。使用前缀失效。不得在 useQuery 与 useInfiniteQuery 之间共享 key。
变更位于 <entity>-mutations.ts。成功后默认 invalidateQueries。工厂 onSuccess = 缓存工作;调用点 mutate(variables, { onSuccess }) = toast/redirect。
状态管理
服务端数据始终使用 TanStack Query,无例外。本地 UI 使用 useState。全局客户端状态使用 Zustand,仅在满足以下条件时:多个组件需要相同客户端状态、需要持久化、需要在 React 树之外访问。派生值内联计算,绝不存储可计算的值。
使用方式
标记为 [detect: …] 的段落标识需要读取的证据。按所展示的关注点选择参考代码。不要从仓库年龄推断兼容性。在进行 entity、query 或 mutation 工作前,先阅读数据访问。在编辑前追踪目标项目的工厂、服务端函数、中间件注册与错误载荷。说明所选层、成功/错误契约、源文件与实质冲突。
适用场景
适用于 React 与 TanStack Start 前端开发,包括路由、页面、组件、状态管理、UI 约定、查询与变更工厂、Feature-Sliced Design 架构落地等任务。
限制
该技能明确不使用 Next.js,不使用 RSC 与 'use client'。Zustand 仅在特定条件下使用,真实应用需要的 store 很少(当前仓库为 0–2 个)。不要为匹配 FSD 图而引入 segment 或 barrel。不要重构无关代码。不要默认使用 select。不要为表单、对话框或重定向编写乐观缓存更新。