Mutate Data Using Forms
In Front-Commerce, you can handle data mutations using Remix's <Form />
component combined with Front-Commerce's GraphQL mutations. This guide explains how to implement form submissions and handle data mutations effectively.
Using Remix Forms
Remix uses <Form />
component as the primary way to mutate data. When a form is submitted, Remix will:
- Call the route's
action
function - Process the form data
- Execute any necessary mutations
- Return a response (redirect or data)
Basic Form Structure
Here's a basic example of a password reset form using our theme components:
import { Form } from "@remix-run/react";
import Stack from "theme/components/atoms/Layout/Stack";
import Fieldset from "theme/components/atoms/Forms/Fieldset";
import FormItem from "theme/components/molecules/Form/Item";
import { Password } from "theme/components/atoms/Forms/Input";
import FormActions from "theme/components/molecules/Form/FormActions";
import { SubmitButton } from "theme/components/atoms/Button";
export default function PasswordResetForm() {
return (
<Form method="post" action="/reset-password">
<Stack desktopSize="2" mobileSize="4">
<Fieldset>
<Stack size="2">
<FormItem key="password" label="Password">
<Password
name="password"
id="password"
autoComplete="new-password"
required
/>
</FormItem>
<FormItem key="confirmation" label="Confirmation">
<Password
name="password_confirm"
id="password_confirm"
autoComplete="new-password"
required
/>
</FormItem>
</Stack>
</Fieldset>
<FormActions>
<SubmitButton appearance="primary">Change password</SubmitButton>
</FormActions>
</Stack>
</Form>
);
}
Handling Form Submissions
When the form is submitted, Remix calls the route's action
function. Here's how to handle the form submission and perform mutations:
import { redirect, type ActionFunctionArgs } from "@remix-run/node";
import { json } from "@front-commerce/remix/node";
import { FrontCommerceApp } from "@front-commerce/remix";
import { YourMutationDocument } from "~/graphql/graphql";
import PasswordResetForm from "../theme/components/PasswordResetForm";
export async function action({ request, context }: ActionFunctionArgs) {
const app = new FrontCommerceApp(context.frontCommerce);
const formData = await request.formData();
const userInput = Object.fromEntries(formData.entries());
if (userInput.password !== userInput.password_confirm) {
return json({ errorMessage: "Passwords do not match" }, { status: 400 });
}
try {
// Execute GraphQL mutation
const result = await app.graphql.mutate(YourMutationDocument, {
newPassword: userInput.password,
});
if (result.resetPassword?.success) {
return redirect("/success-page");
} else {
throw new Error("An error occurred", { status: 500 });
}
} catch (e) {
return json({ errorMessage: "An error occurred" }, { status: 500 });
}
}
export default function AccountPasswordResetPage() {
return <PasswordResetForm />;
}
In the PasswordResetForm
component above, we used the action
property to specify which route will handle the form submission.
However, when using Remix, if your form is defined in the same route that handles its submission (in this case, reset-password.tsx
), you can omit the action
property. Remix will automatically submit the form to the current route's action
function.
For more details, see the Form API documentation.
Key Points
- Use Remix's
<Form />
component - Access form data using
request.formData()
in the route'saction
function - Use
app.graphql.mutate()
to execute GraphQL mutations - Return appropriate responses (redirect, json data or throw an error)