Remix 的主要功能之一是它如何自动使您的 UI 与持久服务器状态保持同步。它分三个步骤进行
让我们考虑一个用户帐户编辑路由。路由模块有三个导出,我们将填充并讨论它们
export async function loader() {
// provides data to the component
}
export default function Component() {
// renders the UI
}
export async function action() {
// updates persistent data
}
路由文件可以导出一个loader
函数,该函数向路由组件提供数据。当用户导航到匹配的路由时,首先加载数据,然后渲染页面。
import type { LoaderFunctionArgs } from "@remix-run/node"; // or cloudflare/deno
import { json } from "@remix-run/node"; // or cloudflare/deno
export async function loader({
request,
}: LoaderFunctionArgs) {
const user = await getUser(request);
return json({
displayName: user.displayName,
email: user.email,
});
}
export default function Component() {
// ...
}
export async function action() {
// ...
}
路由文件的默认导出是渲染的组件。它使用useLoaderData
读取加载器数据
import type { LoaderFunctionArgs } from "@remix-run/node"; // or cloudflare/deno
import { json } from "@remix-run/node"; // or cloudflare/deno
import { useLoaderData, Form } from "@remix-run/react";
export async function loader({
request,
}: LoaderFunctionArgs) {
const user = await getUser(request);
return json({
displayName: user.displayName,
email: user.email,
});
}
export default function Component() {
const user = useLoaderData<typeof loader>();
return (
<Form method="post" action="/account">
<h1>Settings for {user.displayName}</h1>
<input
name="displayName"
defaultValue={user.displayName}
/>
<input name="email" defaultValue={user.email} />
<button type="submit">Save</button>
</Form>
);
}
export async function action() {
// ...
}
最后,当提交表单时,将调用与表单的 action 属性匹配的路由上的操作。在此示例中,它是同一路由。表单字段中的值将在标准request.formData()
API 上可用。请注意,输入上的 name
属性与formData.get(fieldName)
getter 耦合。
import type {
ActionFunctionArgs,
LoaderFunctionArgs,
} from "@remix-run/node"; // or cloudflare/deno
import { json } from "@remix-run/node"; // or cloudflare/deno
import { useLoaderData, Form } from "@remix-run/react";
export async function loader({
request,
}: LoaderFunctionArgs) {
const user = await getUser(request);
return json({
displayName: user.displayName,
email: user.email,
});
}
export default function Component() {
const user = useLoaderData<typeof loader>();
return (
<Form method="post" action="/account">
<h1>Settings for {user.displayName}</h1>
<input
name="displayName"
defaultValue={user.displayName}
/>
<input name="email" defaultValue={user.email} />
<button type="submit">Save</button>
</Form>
);
}
export async function action({
request,
}: ActionFunctionArgs) {
const formData = await request.formData();
const user = await getUser(request);
await updateUser(user.id, {
email: formData.get("email"),
displayName: formData.get("displayName"),
});
return json({ ok: true });
}
当用户提交表单时
fetch
将表单数据发送到路由操作,并且可以通过 useNavigation
和 useFetcher
等 hook 获得待处理状态。useLoaderData
返回服务器的更新值,并且待处理状态恢复为空闲。通过这种方式,UI 可以与服务器状态保持同步,而无需编写任何代码来进行同步。
除了 HTML 表单元素(例如,响应拖放或 onChange 事件)之外,还有多种提交表单的方法。关于表单验证、错误处理、待处理状态等,还有很多要讨论的内容。我们稍后会讨论所有这些,但这只是 Remix 中数据流的要点。
当您从服务器发送 HTML 时,最好让它在 JavaScript 加载之前也能工作。Remix 中的典型数据流会自动执行此操作。流程相同,但浏览器会完成一些工作。
当用户在 JavaScript 加载之前提交表单时
fetch
),并且浏览器的待处理状态会激活(旋转的网站图标)