reset form state within dialog without useEffect?
I'm not exactly sure this is a direct issue with this form library, but i've been struggling on this a while, so gonna post:
i have a form inside a dialog. the dialog is pretty standard and tracks it's own open/close state. whenever it closes i would like to have it reset the form, so in the openChange prop i say something like
if (closing) form.reset()
. for some reason though, this doesn't actually reset the form. i assume it's something to do with the render vs state update cycle?
here's some of the relevant code cut down. is there something obvious going wrong here?
21 Replies
deep-jadeOP•4mo ago
hook:
the thing that's really throwing me for a loop is, the form error does go away if you do the following
- blur the input with a click within the modal, and then close the modal by clicking outside of
it does not go away if you
- click outside of the modal before otherwise invoking blur of the input
i've quickly concluded that i think the blur validation is happening after the modal closes and its state update runs. anyway around this?
been playing with this for a bit.. a bit confused
it seems like basically even though i reset the form, the field metas don't reset with it. the only way i could get this to consistently work is by wrapping the whole form in a check that the modal is open, but i don't even follow why this works. at a loss at this point
flat-fuchsia•4mo ago
does the dialog not completely unrender the form?
I think the reason your solution with the conditional render works may be because it forces the form to completely remount (and thus reset to the defaultValues). So the reset doesn't work, but the rerender creates a new form which never had modified values
deep-jadeOP•4mo ago
but the form that's in the condition should be isolated from my form instance, right?
ie. the lib is headless, so if just the UI is wrapped in a conditional check, shouldn't that not affect the state at all?
flat-fuchsia•4mo ago
depends on if the component wrapping the form is unmounted, which also gets rid of the hook
unless that's not what you meant by the conditional render solution
deep-jadeOP•4mo ago
true. that's probably happening. but it's weird to me that i don't get the same behavior without the condition. if the wrapping component is also unmounting, then a conditional check inside that component shouldn't affect anything?
this is what i have that's working somehow
flat-fuchsia•4mo ago
a reproducible issue on stackblitz could help for testing. Could you list the imports required for it?
deep-jadeOP•4mo ago
I'll get back to this tomorrow hopefully with a repro. https://github.com/jackbisceglia/blank/blob/main/packages/web/src/pages/_protected/%40create-expense.tsx this is the component in question, though the version of it that i have currently works slightly differently with the form not lifted into its own component
flat-fuchsia•4mo ago
Sounds good!
form.reset
currently has some issues with the ordering of updates in React, so this could be a case for that. The main issue with it is being tracked in this PRdeep-jadeOP•4mo ago
i think i've tracked down the issue. no repro so i can try to put it together if nothing makes sense here but basically:
when i leave the modal by clicking outside of it, the following happen in order
- close
- effect that resets form
- form blur event runs
only the children of the modal re-render, so form state persists
i'm not totally sure why this happens though. when i close the form by clicking a button that closes it, the following order happens:
- form blur event runs
- close
- effect that resets form
flat-fuchsia•4mo ago
that sounds logical! See it this way:
When you leave the modal by clicking outside of it
* The modal component captures your click and sees you clicked outside
* It runs the hiding event which includes your
form.reset
* Your previously focused field is removed, so it's blurred and runs the onBlur
event
* This runs blur validation
When you leave the modal with the close button
* Your focus switches from a field to the button, which runs the onBlur
event
* This runs blur validation
* The button's onClick
is triggered, which closes the modal
* The closing modal executes your form.reset
so assuming it's this different condition when everything runs in sync, you can escape the form reset to be outside of the script. Give this a try:
deep-jadeOP•4mo ago
this inside the effect? so basically it pushes the reset to the end of teh call stack
it works. though i see a quick validation error during the modal close. not a huge deal i suppose
flat-fuchsia•4mo ago
wait, from what? closing the modal while you have an invalid form?
deep-jadeOP•4mo ago
yea. because the field is required. it's correct behavior and happens in all cases because the field blur occurs before the modal is done closing
i think this is fine for now. thanks, the setTimeout works nicely
flat-fuchsia•4mo ago
do you have access to the modal state inside the component?
if so, you can add in a condition to not execute it if it's closing
deep-jadeOP•4mo ago
right. brings me back to wrapping the entire form in an isOpen check seems to solve the issue as well. i solved the issue of dialog re-rendering on each keystroke now, so this makes more logical sense now i think:
- close()
- close state updates
- re-render before blur can run?
- because no blur occurred, the field never entered error state
ah but that won't work if blur does end up occurring so i still need the effect
ignore me !
flat-fuchsia•4mo ago
oh, I meant
not sure if the state update will happen before the blur validation. Could be another case where the close button will have weird behaviour
deep-jadeOP•4mo ago
yep that works
flat-fuchsia•4mo ago
in both cases?
deep-jadeOP•4mo ago
well it won't work for cancel but i think that makes sense
sorry
cancel === close button
flat-fuchsia•4mo ago
hmmm, yeah I think there's no easy way around that
deep-jadeOP•4mo ago
i can tolerate a situation where interacting with another part of the form without filling in the required field shows an error, that feels fair. the clickign outside felt awkward
yea
modals have caused me immense pain