Having a form submit a fetch request without making it a server component?
Unanswered
Lithuanian Hound posted this in #help-forum
Lithuanian HoundOP
It's been a bit since I've done NextJS work, but I started by creating a simple form:
But when I load the page with the form, it says
export default function NewStoreForm() {
const submitNewStore = async (data: FormData) => {
const response = await fetch("/stores", {
method: "POST",
body: data,
});
console.log(response);
};
return (
<div>
<Form action={submitNewStore}>
<label htmlFor="name">Name</label>
<input type="text" name="name" id="name" />
</Form>
</div>
);
}
But when I load the page with the form, it says
Error: Functions cannot be passed directly to Client Components unless you explicitly expose it by marking it with "use server".
In this case, it's a fairly simple form that I'm submitting via fetch, as I've done many times in the past. Why does this need to be a server component? Form submissions via fetch are pretty basic Javascript. My first thought was the Form
's action
property, but it seems like this is necessary? Is there no way for me to make a client side form that just sends a request?18 Replies
Brown bear
This is how Form behaves
If you pass a function to
action
then it must be a server functionSo in your case you don't need the fetch
export default function NewStoreForm() {
const submitNewStore = async (data: FormData) => {
const productId = await db.insert(data)
redirect(`/products/${productId}`)
};
return (
<div>
<Form action={submitNewStore}>
<label htmlFor="name">Name</label>
<input type="text" name="name" id="name" />
</Form>
</div>
);
}
Lithuanian HoundOP
Since I'm using a FastAPI backend, I'm guessing I want to use form instead of Form?
Brown bear
No, you just put the endpoint url as the
action
a form submit is just a POST on that endpoint
so if you already have /api/stores
<Form action="/api/stores">
<label htmlFor="name">Name</label>
<input type="text" name="name" id="name" />
</Form>
This should work
Lithuanian HoundOP
Oh, thanks so much! From the way the docs read, this was definitely unclear. If I wanted to do some data manipulation before submitting the form, is there a way?
@Lithuanian Hound Oh, thanks so much! From the way the docs read, this was definitely unclear. If I wanted to do some data manipulation before submitting the form, is there a way?
Brown bear
Sure, if you want to do it on the client then just do the data manipulation in NewStoreForm, if you want to do it on the server then do it in submitNewStore
@Brown bear Sure, if you want to do it on the client then just do the data manipulation in NewStoreForm, if you want to do it on the server then do it in submitNewStore
Lithuanian HoundOP
Sorry, I realize I was unclear. I have an entirely separate API (python). So for example, if I wanted to manipulate the form data before it sends to the BE, how/where would I do that? Both examples you provided seem to suggest using the NextJS api routes? For me at least, that feels like an unnecessary extra step to then send to the Python API.
@Lithuanian Hound Sorry, I realize I was unclear. I have an entirely separate API (python). So for example, if I wanted to manipulate the form data before it sends to the BE, how/where would I do that? Both examples you provided seem to suggest using the NextJS api routes? For me at least, that feels like an unnecessary extra step to then send to the Python API.
Brown bear
If you have a separate API that manipulates the data you either:
1 - use the onSubmit handler instead of calling the server action. in this case you can perform all the fetch logic on the client
2 - perform the fetch to the backend inside the server action itself
1 - use the onSubmit handler instead of calling the server action. in this case you can perform all the fetch logic on the client
2 - perform the fetch to the backend inside the server action itself
@Brown bear If you have a separate API that manipulates the data you either:
1 - use the onSubmit handler instead of calling the server action. in this case you can perform all the fetch logic on the client
2 - perform the fetch to the backend inside the server action itself
Lithuanian HoundOP
Thanks. I wasn't sure if onSubmit would work with Form, based on the docs. I'll stick with that.
Silver Fox
The
action
prop on forms can actually run client-side functions, as detailed in React's documentation ([react.dev/.../form#handle-form-submission-on-the-client](https://react.dev/reference/react-dom/components/form#handle-form-submission-on-the-client)):export default function Search() {
function search(formData) {
const query = formData.get("query");
alert(`You searched for '${query}'`);
}
return (
<form action={search}>
<input name="query" />
<button type="submit">Search</button>
</form>
);
}
So you don't need to handle things with an
onSubmit
or server action if you don't want to 🙂@Silver Fox The `action` prop on forms can actually run client-side functions, as detailed in React's documentation ([react.dev/.../form#handle-form-submission-on-the-client](https://react.dev/reference/react-dom/components/form#handle-form-submission-on-the-client)):
jsx
export default function Search() {
function search(formData) {
const query = formData.get("query");
alert(`You searched for '${query}'`);
}
return (
<form action={search}>
<input name="query" />
<button type="submit">Search</button>
</form>
);
}
Lithuanian HoundOP
That's
form
as in lower case, the native HTML element. I was referencing Form
, the NextJS component.