Also known as #remix.
throwfrom actions will naturally be caught by the nearestErrorBoundary.Route.ComponentProps['actionData']is only useful client-side. Don't spend x-minutes wondering why your console.log insists on being undefined.- Instead of throwing from an action, you can
try/catchand returndata()with astatus: 400.
export async function action({ request }: Route.ActionArgs) {
const formData = await request.formData()
const emailAddress = formData.get("email_address")
if (typeof emailAddress !== "string") {
throw new Error("Expected a string value, but received a File.")
}
try {
const validEmailAddress = z.string().email().parse(emailAddress)
await someSideEffect(validEmailAddress) // like authentication
return data({ ok: true as const, emailAddress }, { status: 200 })
} catch (error) {
if (error instanceof ZodError) {
return data(
{ ok: false as const, emailAddress, error: "validation" as const },
{ status: 400 },
)
}
return data(
{ ok: false as const, emailAddress, error: "unknown" as const },
{ status: 400 },
)
}
}
export default function Route({
loaderData,
actionData,
}: Route.ComponentProps) {
// @NOTE: actionData only exists client-side
return (
<>
{actionData?.ok ? (
<p>hooray!</p>
) : (
<Form method="post">
<input
name="email_address"
placeholder="Email address"
required type="email"
/>
<button>submit</button>
</Form>
)}
</>
)
}
Notes #
- I think it is bizarre that
react-routerdocumentation usesleteverywhere. - It's also weird to
throwtheirredirectfrom actions. That ain't an error.