edmundhung / conform

A type-safe form validation library utilizing web fundamentals to progressively enhance HTML Forms with full support for server frameworks like Remix and Next.js.
https://conform.guide
MIT License
1.8k stars 101 forks source link

[1.0.0] `resetForm: true` doesn't work? #434

Open halljus opened 7 months ago

halljus commented 7 months ago

Describe the bug and the expected behavior

Resetting a form to new default values after a successful submission does not seem to work. Sending a submission.reply({ resetForm: true }) response does reset the form.dirty to false, but the values remain the original ones. The reproduction below illustrates it well, including a workaround.

Conform version

v1.0.0

Steps to Reproduce the Bug or Issue

Full reproduction here:

https://stackblitz.com/edit/remix-run-remix-4j3ltb?file=app%2Froutes%2F_index.tsx

What browsers are you seeing the problem on?

Chrome, Firefox, Microsoft Edge, Safari, Others

Screenshots or Videos

No response

Additional context

No response

edmundhung commented 7 months ago

Thanks for getting me a repo. This reason why it doesn't work is because of the time the lastResult is updated and the time the defaultValue updated is different in Remix 😅 Conform will reset the form the moment lastResult is updated while remix is still revalidating the data and fetching the latest defaultValue.

One solution for now is to delay when you update the lastResult option like this:

lastResult: !isSubmitting ? lastResult : null,
halljus commented 7 months ago

Oh! That's funny, as I used to do exactly that but for a totally different reason (disabling inputs while submitting). I took it out for v1 because it was no longer a problem since you stopped using the Constraint Validation API, but I guess it's still needed - just for a totally different reason. 😅

edmundhung commented 7 months ago

Yeah 😅 This might be resolved with single fetch. I probably should talk to the team and see if they wanna change this behaviour together.

houmark commented 6 months ago

I wanted to get the form back to a clean state. I feel it should always set the state to clean when the form was submitted successfully independently of the form being reset or not but it does not look like that is happening.

Trying to reset the form would also keep the most recent values before save for me, and the proposed workaround did not work, so I did a potentially heavy workaround, where I simply change the form id to the record updated timestamp and that gets the form back to a clean state and retains the fields without resetForm: true.

Any other (cleaner) way?

houmark commented 6 months ago

Maybe adding a utility function on the useForm hook that can set the form to clean state would be nice both for this use case and other use cases - but automatically handling it better would of course be preferred :)

edmundhung commented 6 months ago

Trying to reset the form would also keep the most recent values before save for me

It would be great if you can provide a repo so I can understand it better

Maybe adding a utility function on the useForm hook that can set the form to clean state would be nice both for this use case and other use cases - but automatically handling it better would of course be preferred :)

You can always trigger a form reset manually either with formElement.reset() or dispatching a reset intent with form.reset()

houmark commented 6 months ago

Trying to reset the form would also keep the most recent values before save for me

It would be great if you can provide a repo so I can understand it better

I can try to provide that, but not sure how easy it is to isolate/re-create the issue or if this is due to other parts I have going in the same interface (for example I have a tiptap editor and the implementation there required a less than optimal approach). Changing form id may not be that bad of a fix in the end? It seems like it works pretty well for me and the timestamp (which is the form id key) only changes when saving the record, so it seems to be a fairly decent workaround.

Maybe adding a utility function on the useForm hook that can set the form to clean state would be nice both for this use case and other use cases - but automatically handling it better would of course be preferred :)

You can always trigger a form reset manually either with formElement.reset() or dispatching a reset intent with form.reset()

The one thing I struggle the most with, with this library, is that it uses these proxy objects, so debugging out the form or field does not show the methods available and I have not found a way to do that (maybe you have?). Of course if the docs covered more this would be less of an issue and I totally understand you have not been able to improve on that yet, and I wish I had time and knowledge to help with that.

I'm considering alternative approaches to reseting the form. One way would be to do the reset() on onSubmit which should run after validation, but also, of course, prior to submit/save and potential additional server side validations, so it could be premature. Is there a way to, client side, do this when the response comes back and after validating the response was without errors (that validation and save went okay)? afterSubmit maybe?

edmundhung commented 5 months ago

We should add a tips to the remix integration docs.

JasonColeyNZ commented 2 months ago

I have quite often had to add an effect to reset the form when formdata has loaded...

useEffect(() => { form.reset() // eslint-disable-next-line react-hooks/exhaustive-deps }, [formData])

This has been needed when I have a list route that loads the data next to it in an Outlet in a leaf route. The only way to have the form reset when the new data was loaded.

edmundhung commented 2 months ago

@JasonColeyNZ I have added a tips recently about resetting the form from the Remix action. This is basically the same as what I mentioned in this thread. Hope it helps.

JasonColeyNZ commented 2 months ago

@edmundhung This might work with the actiondata, but it doesn't help the situation of a master detail layout, with record selection on one side, then the selected record in an Outlet. When you navigate to the next record, the record doesn't update, unless a useEffect() is used to reset the form.

JasonColeyNZ commented 2 months ago

@edmundhung OK, I hadn't seen this tip here... https://conform.guide/api/react/useForm#tips regarding adding the data id into the id in useForm, this seems to have fixed this issue for me, excellent, thank you.