// app/routes/products.$id.tsx
import { Form, useLoaderData, useActionData } from "react-router";
import type { LoaderFunctionArgs, ActionFunctionArgs } from "react-router";
import { redirect } from "react-router";
// Server-side data loading
export async function loader({ params, request }: LoaderFunctionArgs) {
const product = await db.products.find(params.id);
if (!product) {
throw new Response("Not Found", { status: 404 });
}
return { product };
}
// Handle mutations
export async function action({ request, params }: ActionFunctionArgs) {
const formData = await request.formData();
await db.products.update(params.id, {
name: formData.get("name"),
price: formData.get("price"),
});
return redirect(`/products/${params.id}`);
}
// Document metadata
export function meta({ data }) {
return [
{ title: `${data.product.name} | My Store` },
{ name: "description", content: data.product.description },
];
}
// Stylesheets
export function links() {
return [
{ rel: "stylesheet", href: "/styles/product.css" },
];
}
// Error UI
export function ErrorBoundary() {
const error = useRouteError();
return <div>Error: {error.message}</div>;
}
// Main component
export default function Product() {
const { product } = useLoaderData<typeof loader>();
return (
<div>
<h1>{product.name}</h1>
<p>{product.description}</p>
<p>${product.price}</p>
<Form method="post">
<input name="name" defaultValue={product.name} />
<input name="price" defaultValue={product.price} />
<button type="submit">Update</button>
</Form>
</div>
);
}