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)
获取器相耦合。
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
之类的挂钩变得可用。useLoaderData
返回来自服务器的更新值,并且待处理状态恢复到空闲状态。这样,UI 就可以与服务器状态保持同步,无需编写任何同步代码。
除了 HTML 表单元素之外,还有多种方法可以提交表单(例如,响应拖放或 onChange 事件)。关于表单验证、错误处理、待处理状态等方面还有很多需要讨论的内容。我们将在后面详细讲解,但这就是 Remix 中数据流的概要。
从服务器发送 HTML 时,最好使其在 JavaScript 加载之前也能正常工作。Remix 中典型的数据流会自动执行此操作。流程相同,但浏览器会完成部分工作。
当用户在 JavaScript 加载之前提交表单时
fetch
),并且浏览器待处理状态激活(旋转的 favicon)。