Remix 很强的一点,是布局、数据和 URL 可以一起嵌套。
例如你有这样的结构:
// app/routes/ships.tsx
import { Outlet, useLoaderData, NavLink } from "@remix-run/react";
import { json } from "@remix-run/node";
import { getShipStats } from "~/models/ship.server";
export async function loader() {
return json({ stats: await getShipStats() });
}
export default function ShipsLayout() {
const { stats } = useLoaderData<typeof loader>();
return (
<div>
<header>
<h1>船舶港区</h1>
<p>今日在港:{stats.inPort}</p>
<nav>
<NavLink to=".">总览</NavLink>
<NavLink to="new">新建船舶</NavLink>
</nav>
</header>
<section>
<Outlet />
</section>
</div>
);
}再配上:
// app/routes/ships._index.tsx
import { useLoaderData } from "@remix-run/react";
import { json } from "@remix-run/node";
import { listShips } from "~/models/ship.server";
export async function loader() {
return json({ ships: await listShips() });
}
export default function ShipsIndexRoute() {
const { ships } = useLoaderData<typeof loader>();
return (
<ul>
{ships.map((ship) => (
<li key={ship.id}>{ship.name}</li>
))}
</ul>
);
}这时候页面结构就是:
root
└── ships.tsx 船舶港区公共框架
└── ships._index.tsx 船舶列表区用户在 /ships 和 /ships/new 之间切换时,父布局可以不重建,只有子泊位在变。
这就是 Remix 的一个关键性能来源:
不是每次整页重来,而是知道哪一层港区还在,哪一层才需要重新靠港。