Reputation: 1738
I'm trying out this new NextJs feature documented here
The base example works whenever action doesn't receive any argument at all.
But I'm wondering how do I pass arguments to the server action.
// someForm.tsx
import { experimental_useFormState as useFormState } from 'react-dom';
import submit from '@/app/actions';
// passing the action as the first argument
const [_formStatus, formAction] = useFormState(submit, {
message: '',
});
// jsx
<form
action={formAction}
>
<input
aria-label='email address'
value='foo'
type='text'
placeholder='Enter your email'
/>
<Button type='submit' pendingMessage='Sending...'>Contact Us</Button>
</form>
as mentioned, this action doesn't take any argument an it works
// app/actions
// what if I'd wanted submit to have arguments from the form?
export default async function submit() {
console.log('submitting');
try {
await new Promise<void>((res) => {
setTimeout(() => {
res();
}, 2000);
});
revalidatePath('/');
return { message: 'Thanks!' };
} catch (e) {
console.error(e);
return { error: 'Error' };
}
}
I tried adding an argument with the type of FormData
but it doesn't work
export default async function submit(formData: FormData) {
no overload matches this call. Overload 1 of 2, '(action: (state: FormData) => Promise, initialState: FormData, permalink?: string | undefined): [state: FormData, dispatch: () => void]', gave the following error. Argument of type '(formData: FormData) => Promise<{ message: string; error?: undefined; } | { error: string; message?: undefined; }>' is not assignable to parameter of type '(state: FormData) => Promise'. Type 'Promise<{ message: string; error?: undefined; } | { error: string; message?: undefined; }>' is not assignable to type 'Promise'. Type '{ message: string; error?: undefined; } | { error: string; message?: undefined; }' is not assignable to type 'FormData'. Type '{ message: string; error?: undefined; }' is missing the following properties from type 'FormData': append, delete, get, getAll, and 7 more. Overload 2 of 2, '(action: (state: FormData, payload: unknown) => Promise, initialState: FormData, permalink?: string | undefined): [state: FormData, dispatch: (payload: unknown) => void]', gave the following error. Argument of type '(formData: FormData) => Promise<{ message: string; error?: undefined; } | { error: string; message?: undefined; }>' is not assignable to parameter of type '(state: FormData, payload: unknown) => Promise'. Type 'Promise<{ message: string; error?: undefined; } | { error: string; message?: undefined; }>' is not assignable to type 'Promise'.ts(2769)
Upvotes: 7
Views: 6986
Reputation: 1
Agreed you need to add input elements with a name.
For adding hard coded values.
I saw in a tutorial binding to the function but that doesn't play nice with typescript:
<form action={addToCart.bind(product.id)}>
I needed to add a few hard coded properties so I used a "json field" like this:
<form action={addToCart}>
<input type="hidden" name="json" value={JSON.stringify({productId: product.id, variant: product.variants[0].id, qty: 3})} />
<button>Add to cart</button>
</form>
Upvotes: 0
Reputation: 381
You can pass values via input
elements.
The thing you forgot is to give those inputs a name
attribute.
//...
<input
name="email"
aria-label="email address"
value="foo"
type="text"
placeholder="Enter your email"
/>
And in the action you need to pass the FormData and prevState arguments:
export default async function submit(prevState, formData) {
// getting your input value
const email = formData.get("email");
// ...
}
Here's an official example for reference.
Upvotes: 3