Support raw-object submissions to actions (bypass Request serialization) #9858
Replies: 8 comments 1 reply
-
You can submit a plain object (non-nested) and it will be serialized into the request form data:
Does that handle your use case? |
Beta Was this translation helpful? Give feedback.
-
Hi, thanks for replying and apolgies for getting back to you so late. I didn't know about that feature so it's good to know as it helps a little. Knowing that I could do the following: import { useForm } from "react-hook-form";
import { useSubmit } from "react-router-dom";
import { set } from "lodash";
export default function App() {
const { register, handleSubmit, formState: { errors } } = useForm();
const submit = useSubmit();
const onSubmit = data => submit(data);
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input {...register("name.first")} />
<input {...register("name.last", { required: true })} />
{errors.name.last && <span>This field is required</span>}
<input type="submit" />
</form>
);
};
export const action = async ({ request }) => {
const user = request.formData().entries().reduce((acc, [key, val]) => set(acc, key, val), {});
await API.graphql(graphqlOperation(createUser, { input: user }));
}; The action will accept the key/value formdata object and re-parse it back into a structured object. This approach has some flaws though, e.g. there's a difference in how react-form-hook handles arrays and how lodash set does: Lodash I think parsing the results in and out of formdata is not a nice approach. If it was possible to send a js object directly to the action that would make the scenario of using a graphql API and a form library much better. |
Beta Was this translation helpful? Give feedback.
-
We're pretty happy leveraging standardized web APIs such as import { useForm } from "react-hook-form";
import { useSubmit } from "react-router-dom";
import { set } from "lodash";
export default function App() {
const { register, handleSubmit, formState: { errors } } = useForm();
const submit = useSubmit();
const onSubmit = data => submit({
// You can implement any custom serialization logic here
serialized: JSON.stringify(data)
});
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input {...register("name.first")} />
<input {...register("name.last", { required: true })} />
{errors.name.last && <span>This field is required</span>}
<input type="submit" />
</form>
);
};
export const action = async ({ request }) => {
let formData = await request.formData();
// And then just parse your own format here
let user = JSON.parse(formData.get('serialized'));
await API.graphql(graphqlOperation(createUser, { input: user }));
}; |
Beta Was this translation helpful? Give feedback.
-
@brophdawg11 Your solution is only a workaround as serialization is an unnecessary step if we can transfer a reference to an object. It would be better to add the customData parameter to the SubmitFunction export interface SubmitFunction {
(
/**
* Specifies the `<form>` to be submitted to the server, a specific
* `<button>` or `<input type="submit">` to use to submit the form, or some
* arbitrary data to submit.
*
* Note: When using a `<button>` its `name` and `value` will also be
* included in the form data that is submitted.
*/
target: SubmitTarget,
/**
* Options that override the `<form>`'s own attributes. Required when
* submitting arbitrary data without a backing `<form>`.
*/
options?: SubmitOptions
/**
* User data
*/
customData?: any): void;
} and next pass customData as the third parameter to an action: export interface ActionFunctionArgs extends DataFunctionArgs {
customData?: any;
} Like @connelhooley I use graphql mutations (Relay), but my form outputs are typed objects obtained from Formik. The new react-router version with loaders is fantastic, and it's great step forward as we all need render-as-you-fetch. However, the library needs some additional features to be truly useful. |
Beta Was this translation helpful? Give feedback.
-
Could someone please tell why doesn't the example above work for me? Here's it is in a sandbox. https://codesandbox.io/s/nice-pike-zy3hqc?file=/src/index.js I am content if I can just console.log the value inside the action. I can take it from there. Thank you. |
Beta Was this translation helpful? Give feedback.
-
I figure it out. I had to use the fetcher to pass the data to action. import { useForm } from "react-hook-form";
import { useFetcher } from "react-router-dom";
export default function App() {
const fetcher = useFetcher();
const {
register,
handleSubmit,
formState: { errors }
} = useForm();
const onSubmit = (data) =>
fetcher.submit(
{
// You can implement any custom serialization logic here
serialized: JSON.stringify(data)
},
{ method: "post", action: "/" }
);
return (
<fetcher.Form onSubmit={handleSubmit(onSubmit)}>
<input {...register("first")} />
<input {...register("last", { required: true })} />
{errors?.name?.last && <span>This field is required</span>}
<input type="submit" />
</fetcher.Form>
);
}
export const action = async ({ request }) => {
console.log("action called....");
let formData = await request.formData();
// And then just parse your own format here
let user = JSON.parse(formData.get("serialized"));
console.log(user); // <== I am content if this console.log works
return null;
}; |
Beta Was this translation helpful? Give feedback.
-
I'm going to convert this to a discussion so it can go through our new Open Development process. Please upvote the new Proposal if you'd like to see this considered! |
Beta Was this translation helpful? Give feedback.
-
Good news folks! We're going to add support for this and have written up the expected API in a new proposal (#10324), so I'm going to close this out and please refer to the linked proposal for future progress here. We hope to start work on this soon. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
What is the new or updated feature that you are suggesting?
I would like to submit a request via GraphQL when I submit a form. I am using react-hook-form to validate and format the object I want to submit. I know the docs recommend using browser validation but I would prefer to keep react-hook-form if possible. There's an awful lot of stuff it handles for me. E.g. handling repeatable inputs, formatting all the fields into a structured object.
If I could pass an object into an action from my component via the
useSubmit
hook, this would unlock a lot more scenarios forreact-router
imo.E.g. something like this:
Is there a better way to do this without such a feature? I can't see an obvious and nice way to invoke a graphql mutation without ditching react-form-hooks. This would mean I:
Maybe I shouldn't be using actions but my "OCD" is telling me that if I'm using loaders (which work great with GraphQL, there's docs for it), I should be using actions!
Why should this feature be included?
Beta Was this translation helpful? Give feedback.
All reactions