airjp73 / rvf

Easy form validation and state management for React and Remix
https://rvf-js.io
MIT License
827 stars 66 forks source link

[Bug]: GET url param is not updated after using useFormContext submit #302

Closed justb3a closed 1 month ago

justb3a commented 1 year ago

Which packages are impacted?

What version of these packages are you using?

"@remix-validated-form/with-zod": "2.0.6",
"remix-validated-form": "5.0.2",

Please provide a link to a minimal reproduction of the issue.

https://codesandbox.io/s/billowing-flower-q3cj9m?file=/app/routes/index.tsx

Steps to Reproduce the Bug or Issue

In the demo

  1. Click on "set to Jane", see that the value changes BUT the GET URL param is not updated.
    • ?__rvfInternalFormId=the-form&name=John
    • Change in input field, value is updated and GET param as well -> ?__rvfInternalFormId=the-form&name=Gordon
    • Set the value and update it via "submit", the value is updated, the GET param not

Expected behavior

When using const { submit } = useFormContext('formId'), setting a value controlled with useControlField and then submitting the form using submit should also update the GET param in the url (worked in version 4.x before updating to 5.x).

  const onSubmit = useCallback(() => {
    setNameValue("Jane");
    submit();
  }, [submit, setNameValue]);

Screenshots or Videos

Screenshot 2023-06-23 at 13 44 44

Platform

macos latest firefox and chrome

Additional context

No response

airjp73 commented 1 year ago

This is caused by one of the breaking changes in v5. In the release notes, it's the section titled Values in the form are now captured before validation occurs.

The issue is that setValue from useControlField is asynchronous (like React's own setState), while submit is synchronous. Before, there was an issue where you could submit the form and then change the form values, which has been fixed. This is essentially what's happening here. submit is kicking off the submit before the content of the form has actually been updated in response to updating the controlled field. You can see this in your reproduction as well.

I think this case is still fixable though. We have an internal awaitValueUpdate helper we use when validating individual fields, and I think we should add it to the submission handler function before we capture the form values.

I won't have time to push a fix until at least Monday, so in the meantime you can make your onSubmit an async function and await Promise.resolve() before you submit.

setNameValue("Jane");
await Promise.resolve();
submit();
justb3a commented 1 year ago

Thanks for the fast response and the explanation, having a fix for this would be great. At the moment / as a quick fix I use the useSubmit hook from @remix-run/react:

import { useSubmit } from '@remix-run/react'

const submitForm = useSubmit()

submitForm({
   __rvfInternalFormId: formId,
  name
 })

It works but doesn't feel right 😎 What also did work was using a button type="submit" onClick={…}, on click setting the values and then using the native button submit functionality, but the button has always to be available in the markup inside the ValidatedForm (no conditional rendering) and it didn't feel really safe timing wise.

justb3a commented 11 months ago

hei again, time flies, is there any update? Would be great if you could add the usage of the internal awaitValueUpdate helper. πŸ™

I just had to use again the await Promise.resolve() quick fix including documentation why. Would be great to get rid of this at some point. Thanks.

airjp73 commented 1 month ago

RVF v6 has been released πŸŽ‰

This should no longer be a problem in v6. If it's still a problem in that version, please feel free to open a new issue.

You can find the documentation here and the migration guide here.