T
TanStack2mo ago
wise-white

Does the defaultState property in useForm work?

Hi, I'm testing tanstack-form but something is strange. On mount, I need that the form state isFieldsValid has to be false by default to prevent user submit unfilled form at start. It seems the best way to do it is to set isFieldsValid property inside the defaultState in the useForm hooks. But, no matters if I set in the property like defaultState: { isFieldsValid: false } , by default, isFieldsValid stay always true on mount and I can't rely on it to handle disable state for my submit button. I found a "workaround" to force the isValid state to false directly in the input mais it's not the best. With this, your should set manualy the property in every input in your form so... not optimized (I tried to do so for the entire form but it's not working too). You can reproduce the behaviour and test the workaround in this Codesandbox -> https://codesandbox.io/p/devbox/strange-lederberg-4xjp7l Am I doing something wrong or any advice on this ?
8 Replies
xenial-black
xenial-black2mo ago
I believe defaultState is too loosely typed in its current state. You're trying to set a derived value which will be overwritten as soon as the dependencies are set now, you could set error maps from the base state and manage all of that, but it seems overkill for what you're trying to achieve: disable the submit button at the start. Try using form.isPristine as a check instead keep in mind that you need to subscribe to the meta value to make sure it's reactive:
<form.Subscribe selector={state => state.isPristine}>
{reactiveIsPristine => <></>}
</form.Subscribe>
<form.Subscribe selector={state => state.isPristine}>
{reactiveIsPristine => <></>}
</form.Subscribe>
wise-white
wise-whiteOP2mo ago
Thanks for your answer 👍 I see. The problem with isPristine is that it's for the entire form. If you have a real form with several inputs, as soon as you type 1 char in the first input, isPristine is false, like here -> https://codesandbox.io/p/devbox/festive-shamir-6g2tyh It's why I try to handle this with the isFieldsValid, to know when all the fields are valid and have them false at start.
xenial-black
xenial-black2mo ago
with field-level validation, that will happen, yes. The main concern is that field validators don't run if the field isn't interacted with as you were able to see. Only on submission will they be checked to ensure everything's valid before final submission. Form validators are run on any field's change and can collect errors for untouched fields too. That would allow you to detect that not all fields are valid yet. It leaves two problems though, which is how to show errors (since untouched fields shouldn't show any) and how to set field-level errors from the form Since untouched fields have isTouched: false, you can hide errors on fields if they are not touched. This still keeps track of the errors behind the scenes like you want. As for setting field-level errors, see this section in Form Validation
wise-white
wise-whiteOP2mo ago
I also tried this approach (Setting field-level errors from the form's validators) but if I want a specific flow to handle validation and display error I need to handle them at the field-level but not from form's validators. For example, if I want this flow: 1. All inputs are empty -> submit button disable 2. User start to fill the first input (I don't want display error for the moment because it's the "first try to fill") Example with email input, just fill "example@" 3. User go to the second input and then the first input (isOnBlurred) is in error and stay that way until it's filled correctly (handle with onChange on field) 4. Same for second input 5. All inputs are filled correctly -> submit button active
wise-white
wise-whiteOP2mo ago
As the onTouched mode on react hook form -> https://react-hook-form.com/docs/useform#mode
Performant, flexible and extensible forms with easy-to-use validation.
xenial-black
xenial-black2mo ago
would that not be achievable with
// form-level validator set an error on this field

field.state.meta.isBlurred // the field must have been blurred before
&& !field.state.meta.isValid // and it is not valid
&& errors // which will reveal the error present for the field
// form-level validator set an error on this field

field.state.meta.isBlurred // the field must have been blurred before
&& !field.state.meta.isValid // and it is not valid
&& errors // which will reveal the error present for the field
if the user does not blur it before making a correct field, then the error is gone by the time it is blurred so visually, nothing changes. Behind the scenes, you preserve the error the submit button would be disabled={isPristine || !canSubmit} I'll fork the sandbox to show what I mean :PepeThumbs: since there's an unrelated issue in it. onChange is not an option, you're probably looking for listeners.onChange https://codesandbox.io/p/devbox/patient-thunder-9fdpf3?workspaceId=ws_E6nrAeNP67wQGvhfb82TxH here you go! pretty sure this is fitting to your description @GDHU added some debug stuff so you can view what's going on hmm, there's one thing missing still. If you don't change any values, it will mark it as blurred but not as touched. You can add this logic as well:
listeners: {
onChange: ({ value }) => console.log("------- onChange", value),
// we want to avoid duplicating errors, but we want onChange validation to show up if a user
// blurs a field without changing the value. Trigger the change validation manually
onBlur: ({ formApi }) => formApi.validate("change"),
},
listeners: {
onChange: ({ value }) => console.log("------- onChange", value),
// we want to avoid duplicating errors, but we want onChange validation to show up if a user
// blurs a field without changing the value. Trigger the change validation manually
onBlur: ({ formApi }) => formApi.validate("change"),
},
you might've noticed that dynamic validation (like revalidateMode in RHF provides) is somewhat bulky to do right now. We're addressing that in this PR, which will also allow us to ease some transitions for users like RHF
wise-white
wise-whiteOP2mo ago
Alright, I will check on that too. Thanks for the answers and updated codesanbox 👍🙏 I will start from it to do some more tests.
xenial-black
xenial-black2mo ago
keep me updated if you have more questions :Prayge:

Did you find this page helpful?