想去哪里?

首页 页面 关于 页面 项目 页面 简历 页面 技术 页面 随笔 页面 联系 页面 隐私政策 页面 Terminal Spike 隐私政策 页面 用 Astro 构建文档与职业个人网站 技术 通过 tmux、Mosh、Termius 与 Tailscale 随处使用 Codex 技术 用 Langfuse 观察 Codex 的 MCP 工具调用 技术 产品应用中的本地化 技术 把 MCP 作为安全的 AI 集成边界 技术 用 Zod、OpenAPI 与 Swagger 维护 API 契约 技术 用 pg-boss 运行持久后台任务 技术 通过真实知识工作流理解 pgvector 与 RAG 技术 Pi Edge:让 Pi 待在 Obsidian 笔记旁 技术 为真实排序任务设计拖放交互 技术 Prisma 与 PostgreSQL:产品状态的事实来源 技术 把 Ralph Loop 当作计划队列 技术 用 React Router 组织全栈产品工作流 技术 把 shadcn 风格组件变成自己的产品系统 技术 用表格与编辑器承载密集业务操作 技术 Terminal Spike:原生 Android 终端 技术 在 Linux 上用 fcitx 输入带声调的拼音 技术 在 Linux 上配置 DEFT Pro 轨迹球 技术 在 KOReader 上使用 Pocket 稍后读 技术 为 Vercel AI SDK 设置明确的工具边界 技术 垂直切片架构与 dependency-cruiser 技术 用 Vitest 与 Playwright 测试产品工作流 技术 我的随处工作流:Herdr、code-server、Obsidian 与 Pi Edge 技术 Zod 不只是校验 技术 《卡拉马佐夫兄弟》是我看过最好的小说 随笔 基督徒口述1960劳改历史 随笔 圣经中的“道”与言语 随笔 我们爱,因为神先爱我们,而不是空洞的“自爱” 随笔 妈妈,让我来承担爸爸的过错吧 随笔 我与神的故事 随笔 世界远离上帝,接近中国 随笔 “爱的五种语言”和内外向,只存在于语言中 随笔 人格类型不存在,你在世界而非概念中生活 随笔 危险的词语:为什么心理学是不可能的 随笔 2000 年,一个深圳打工者的故事 随笔 阿联酋Ras al Khaimah见闻录 随笔 沙甸:1975 年的一场冲突 随笔 关于中国的纪录片 随笔
← 技术/工程实践

用 React Router 组织全栈产品工作流

让 loader 与 action 明确用户任务,同时避免把所有规则塞进路由。

路由不只是 URL,在产品里,它往往代表用户要完成的任务。

这会改变代码设计。启动导入的设置页不只是一块屏幕,还包含当前状态、校验、权限检查、提交、跳转和失败状态。它们散落各处时,流程就难以理解。

React Router 的 loader 与 action 提供了简单、明确的页面边界:

export async function loader() {
  return getImportStatus();
}

export async function action({ request }: ActionFunctionArgs) {
  const formData = await request.formData();
  const result = await startImportFromForm(formData);
  return redirect(`/settings/imports/${result.jobId}`);
}

loader 回答“展示页面前用户需要什么”,action 回答“提交表单后发生什么”。

路由不应包办所有决定。上传文件所需的校验、权限、幂等键和后台任务,应放入服务。路由协调 Web 边界,服务负责产品规则。

const result = await startImportFromForm(formData);

路由不必知道导入处理的所有细节,只需把用户请求变成下一个可见状态。

这也是产品设计:启动慢任务后,不要让用户停在冻结的表单上。跳转到状态页能明确告诉他请求已接受、有任务 ID,并展示排队、运行、完成或失败。

第一版把流程写进一个 action 是合理的快速交付方式。但如果规则只存在于 action,就会难以脱离浏览器测试,也难以从其他入口复用。

我通常区分这些边界:路由处理表单、响应、跳转和路由错误;schema 校验外部输入;服务决定工作流含义;repository 或数据库层持久化;界面以用户可操作的方式展示状态。

任务自然对应页面和表单时,React Router 很适合。高度实时、画布型或主要依赖本地状态的交互则不同,路由可能只是交互客户端的薄壳。

loader 和 action 太方便,容易诱使我们把一切放进去。清晰服务背后的薄路由,通常更容易测试和修改。

我的判断方式是:读路由就能解释用户任务,不渲染页面也能测试业务规则,边界大概就放对了。