跳转到内容

Remix — 拥抱 Web 标准的 React 全栈框架

是什么

Remix 是 Ryan Florence 和 Michael Jackson(React Router 的作者)做的 React 全栈框架。它的理念一句话:“不打架 Web 平台,强化它”

日常类比:next-js 是给 React 加了一座宫殿,里面什么都自己造一套;Remix 是把现有的胡同改造成顺畅的步行街——少加少减,让浏览器原生能力(fetch、form、URL)更好用。

你写一个 Remix 路由长这样:

routes/posts.tsx
export async function loader() {
return json(await db.posts.findMany())
}
export default function Posts() {
const posts = useLoaderData<typeof loader>()
return <ul>{posts.map(p => <li key={p.id}>{p.title}</li>)}</ul>
}

数据从服务端 loader 来,组件直接 useLoaderData() 拿——不用 useEffect、不用 fetch、不用 loading state

为什么重要

理解 Remix 的设计哲学,能解释这些事:

  • 为什么 React 全栈这么难做:客户端状态管理、数据获取、错误处理、表单提交——每个问题都有一堆库。Remix 用 Web 标准(fetch + form)把它们一次解决
  • 为什么 React Router v7 突然变得像 Next.js:2024 年 Shopify 收购 Remix 后,团队把 Remix 的能力全量并入 React Router——v7 = 新版 React Router + Remix
  • 为什么”渐进增强”重要:Remix 默认 JS 不加载也能用(form 走原生提交),符合 Web 平台几十年的可访问性传统
  • 为什么 Nested Routes 是个大事:路由嵌套对应 UI 嵌套,这是 React Router 的发明,被 next-js App Router 抄过去

核心要点

Remix 的心智模型可以拆成 三件套

  1. loader(服务端获取数据):每个路由可以导出一个 loader 函数,在服务端跑,返回的数据通过 useLoaderData() 给组件用。类比:每个页面有自己的”数据厨房”,组件只是端盘子的服务员

  2. action(处理表单提交):每个路由可以导出一个 action 函数,处理 POST/PUT/DELETE 请求。配合 <Form> 组件,不用 onSubmit、不用 fetch——浏览器原生表单提交直接走到 action

  3. component(渲染):默认导出的 React 组件。它只关心怎么渲染,不关心数据从哪来、提交到哪去——这两件事 loader / action 已经做了

加上 嵌套路由:URL /products/123 对应 routes/products.tsx(layout)+ routes/products.$id.tsx(详情页)。layout 包详情页,两个 loader 并行跑,不像传统 SPA 串行等待。

实践案例

案例 1:loader + 组件三件套

// app/routes/posts.$slug.tsx
import { json, type LoaderFunctionArgs } from "@remix-run/node"
import { useLoaderData } from "@remix-run/react"
export async function loader({ params }: LoaderFunctionArgs) {
const post = await db.post.findUnique({ where: { slug: params.slug } })
if (!post) throw new Response("Not Found", { status: 404 })
return json({ post })
}
export default function Post() {
const { post } = useLoaderData<typeof loader>()
return <article><h1>{post.title}</h1><p>{post.body}</p></article>
}

注意:throw new Response 直接走错误边界,不用 try/catch。

案例 2:Form + action 不写一行 fetch

app/routes/contact.tsx
import { Form, redirect, type ActionFunctionArgs } from "@remix-run/react"
export async function action({ request }: ActionFunctionArgs) {
const formData = await request.formData()
await sendEmail({
name: formData.get("name") as string,
message: formData.get("message") as string,
})
return redirect("/thanks")
}
export default function Contact() {
return (
<Form method="post">
<input name="name" required />
<textarea name="message" required />
<button type="submit">发送</button>
</Form>
)
}

JS 不加载也能用:浏览器原生 form 提交→ 服务端 action 处理 → redirect 到 thanks。JS 加载后,Remix 把它升级成 fetch 提交,无刷新。

案例 3:Nested Routes

app/routes/
├── products.tsx (layout: 顶部分类筛选)
├── products._index.tsx (列表页)
└── products.$id.tsx (详情页)

访问 /products/42

  • products.tsx 的 layout 渲染(包含 <Outlet />
  • products.$id.tsx 的详情在 Outlet 里渲染
  • 两个 loader 并行:layout 的分类数据 + 详情数据同时拿,不串行

踩过的坑

  1. 学习曲线对 React-only 的人陡:习惯了 useState + useEffect + fetch 的人会困惑——“为什么不用 onSubmit?“答案是:Web 表单标准比 React 早 30 年,Remix 让你用回它。但要扭转心智

  2. client-only 状态反而麻烦:复杂的客户端全局 store(Zustand / Redux)没有官方位置——Remix 假设你 90% 状态是”服务端的数据”。剩下 10% 你得自己接

  3. Remix v2 与 v1 路由约定有调整:v1 用文件夹(routes/posts/$slug.tsx),v2 用扁平命名(routes/posts.$slug.tsx)。老教程经常错位

  4. 2024 年 Remix → React Router v7 合并:术语切换让老文档失准——现在新项目应该用 react-router@7(带 framework mode),而不是 @remix-run/*。Remix v2 仍维护,但 v3 不会有了

  5. 部署需要 Node 服务端:Remix 默认 SSR,不像 next-js 那样可以纯静态导出。要放 CDN 得用 Cloudflare Workers / Deno Deploy 等边缘运行时

适用 vs 不适用场景

适用

  • 内容驱动的网站(博客、文档、电商)—— loader 拿数据 + form 提交,全套丝滑
  • 强调可访问性、SEO、首屏速度的项目 —— 服务端渲染 + 渐进增强
  • 团队熟悉 Web 平台标准(fetch、Response、FormData)—— Remix 的 API 几乎就是 Web API
  • 想从 Next.js Pages Router 迁移但又不想接受 App Router 的 RSC 复杂度

不适用

  • 纯客户端 SPA(管理后台、画板工具)—— Remix 的卖点用不上,反而被 SSR 拖累
  • 需要完全静态导出(GitHub Pages 这种)—— 默认要 Node 运行时
  • 团队已经深度绑定 next-js 生态(next-image / next-auth / vercel) —— 切换成本不值
  • 2025+ 新项目:直接用 React Router v7 framework mode,别再用 @remix-run/*

学到什么

  1. Web 标准不是包袱,是资产:fetch / Form / URL / Response 这些 30 年沉淀的东西,比任何框架抽象都稳定。Remix 让你用回它们
  2. 数据流从”哪里取”开始定,不从”怎么存”开始:loader 决定数据源 → 组件直接用,跳过了”全局 store + selector + action”的传统三件套
  3. Nested Routes 不是路由的事,是 UI 的事:URL 嵌套 = layout 嵌套 = loader 并行——三件事用一个机制解决
  4. 框架可以”少而对”:Remix 核心 API 只有几十个,但每个都是 Web 标准的薄包装。比起 next-js 的”全功能”,是另一种产品哲学

延伸阅读

关联

  • next-js —— Remix 的最大对手;两者哲学相反,Remix 拥抱 Web 标准,Next 自建一套
  • react-router —— Remix 的”娘家”;2024 年合并后 React Router v7 = Remix
  • astro —— 同样追求”Web 标准 + SSR”,但做内容站,不做交互应用
  • shadcn-ui —— 常和 Remix 配合用的 UI 方案

反向链接

  • ape-framework —— Ape Framework — Python 智能合约开发一条龙
  • astro —— Astro — 内容站点优先的 Web 框架
  • conform —— Conform — 让浏览器原生 form 也能 type-safe 校验
  • next-js —— Next.js — React 全栈框架
  • shadcn-ui —— shadcn/ui — 把 React 组件从 npm 包变成”源码 + CLI 协议”
  • sveltekit —— SvelteKit — Svelte 全栈框架
  • tanstack-router —— TanStack Router — 把 URL 当类型,编译器替你守路由