App reviews, troubleshooting, and recommendations
We're moving the community! Starting July 7, the current community will be read-only for approx. 2 weeks. You can browse content, but posting will be temporarily unavailable. Learn more
So we are trying to do some validation for our cart using the barebones Hydrogen quickstart in TypeScript, but we are having issues using the CartForm component.
Whenever you submit a cart form to update some attributes, Hydrogen uses the <CartForm> component like a form.
// in app/components/Cart.tsx
function CartLineUpdateButton({ children, lines, }: { children: React.ReactNode; lines: CartLineUpdateInput[]; }) { return ( <CartForm route="/cart" action={CartForm.ACTIONS.LinesUpdate} inputs={{lines}} > {children} </CartForm> ); }
By default, we are given an action in `app/routes/($locale).cart.tsx` that receives the submitted information.
// in app/routes/($locale).cart.tsx
export async function action({request, context}: ActionFunctionArgs) { ... return json( { cart: cartResult, errors, analytics: { cartId, }, }, {status, headers}, );
Typically in React, the action returns information to whatever route submitted the form with "useActionData". You can see an example in the official React documentation: https://reactrouter.com/en/main/hooks/use-action-data#useactiondata
export default function SignUp() { const errors = useActionData(); return (
<Form method="post"> ... <p> <button type="submit">Sign up</button> </p> </Form> ); }
However, when attempting to receive information from the built-in action in `app/routes/($locale).cart.tsx`, the value always comes back as "undefined". This is even after returning to the page, forcing a reload.
// in app/routes/($locale).cart.tsx
export default function Cart() { const actionData = useActionData(); console.log("action data: " + actionData); // always undefined
How can we receive this information? Where does it go? We would like to use the "errors" value for some form validation, and display any errors. But without the action's return value, we can never display anything in addition. We could use some help figuring this out.
You can try adding a "fetcherKey" to the Form and then use the "useFetcher" hook with that key to get the result of the form action.
https://remix.run/docs/en/main/components/form#fetcherkey
https://remix.run/docs/en/main/hooks/use-fetcher#key
Adding a fetcherKey only gives me the result {"Form":{},"state":"idle"} , which is not the format as the action.
function CartLineUpdateButton({
children,
lines,
}: {
children: React.ReactNode;
lines: CartLineUpdateInput[];
}) {
const fetcher = useFetcher({key: "cart-increment"});
console.log(JSON.stringify(fetcher));
return (
<CartForm
fetcherKey='cart-increment'
route="/cart"
action={CartForm.ACTIONS.LinesUpdate}
inputs={{lines}}
>
{children}
</CartForm>
);
}
What is this information, and how can we get the component to update when the form is submitted without refreshing the page? Is an effect required?
You can try to retrieve the "fetcher.data" result with "useEffect"
function CartLineUpdateButton({
children,
lines,
}: {
children: React.ReactNode;
lines: CartLineUpdateInput[];
}) {
const fetcher = useFetcher({key: "cart-increment"});
useEffect(() => {
console.log('fetcher.data', fetcher.data)
}, [fetcher.data])
return (
<CartForm
fetcherKey='cart-increment'
route="/cart"
action={CartForm.ACTIONS.LinesUpdate}
inputs={{lines}}
>
{children}
</CartForm>
);
}
That still won't work. The effect never updates, and fetcher from "cart-increment" is always '{"Form":{},"state":"idle"}', even when it fails to update.
Hmm, I think you can try this hook: https://github.com/Weaverse/pilot/blob/main/app/hooks/useCartFetchers.tsx
It looks like I was checking the value of the fetcher through a console.log in the code, not in the returned JSX.Element. When I use the fetcher in the element, everything displays correctly.
const fetcher = useFetcher({key: 'cart-increment'});
console.log(JSON.stringify(fetcher)); // "{"Form":{},"state":"idle"}"
return (
<CartForm
route="/cart"
action={CartForm.ACTIONS.LinesUpdate}
fetcherKey="cart-increment"
inputs={{lines}}
>
{/* {"Form":{},"state":"idle","data":{"cart":{"id":"gid://shopify/Cart/... */}
<span>{JSON.stringify(fetcher)}</span>
{children}
</CartForm>
);
It looks like this gets the information that the form submits, but not necessarily the information we were looking for.
We're still trying to obtain the returning information from the Cart "Action". I don't know how to access and display this information on the front-end:
return json(
{
cart: cartResult,
errors,
analytics: {
cartId,
},
},
{status, headers},
);