下面是一个典型的 Remix 路由模块:
// app/routes/ships.$shipId.tsx
import type { LoaderFunctionArgs, ActionFunctionArgs } from "@remix-run/node";
import { json, redirect } from "@remix-run/node";
import { Form, useLoaderData } from "@remix-run/react";
import { getShipById, updateShipStatus } from "~/models/ship.server";
export async function loader({ params }: LoaderFunctionArgs) {
const ship = await getShipById(params.shipId!);
if (!ship) {
throw new Response("船舶不存在", { status: 404 });
}
return json({ ship });
}
export async function action({ request, params }: ActionFunctionArgs) {
const formData = await request.formData();
const status = formData.get("status");
await updateShipStatus(params.shipId!, String(status));
return redirect(`/ships/${params.shipId}`);
}
export default function ShipDetailRoute() {
const { ship } = useLoaderData<typeof loader>();
return (
<main>
<h1>{ship.name}</h1>
<p>当前状态:{ship.status}</p>
<Form method="post">
<button type="submit" name="status" value="arrived">
标记为已到港
</button>
<button type="submit" name="status" value="departed">
标记为已离港
</button>
</Form>
</main>
);
}这个文件里,其实已经出现了 Remix 的完整闭环:
loader负责读取当前船的数据- 组件负责展示
<Form>负责提交action负责写入redirect负责动作完成后的航线跳转
这就是 Remix 的味道:
读写都挂在路由上,UI 只是这个泊位的外立面。