Instructor: So now I also wanna validate
on every keystroke,
hence we can also copy this validation logic
to the name and put change handler,
but actually doing it like that would be incorrect
because here we check if it's not valid
and set this to not valid if it is,
but actually of course, I wanna check if it is valid
on every keystroke
to get rid of that validation error as quickly as possible.
Hence, here, I wanna check
if it's not equal to an empty string
and then set entered name is valid to true.
And we don't need to return here, by the way,
because there is no code to execute after the if statement.
The same here in the blur handler,
we can get rid of return there.
So now in name input change handler,
we are validating the input.
We are setting this to true
as soon as we do detect a valid input.
Though here as a side note,
we shouldn't use the entered name state,
but instead event target value,
because we do update the entered name state with this line,
but as you learned,
such state updates are then scheduled by react,
they are not processed immediately,
so in the next line thereafter,
you don't have that latest state yet,
hence here you would be referring to an old state
if you used entered name.
So therefore instead of doing that,
we should use the same state data source
we used for updating the state in the line before,
which is the event target value here.
Now with that, if we save this,
if we start typing here,
with every keystroke, we update this.
So now we might have the best possible solution here.
Now, we get this instant validation once it blurs
or once we submit,
but then if we have an error.
So if we do, for example, blur with an invalid value,
we do give immediate feedback
and allow the user to directly fix this
with every keystroke.
And I think this is a rather good user experience.
What's not so good though, is our code,
because we wrote a lot of code for just one input.
Now, there will be ways of reusing logic,
and I'll come back to those,
but I wanna start with cleaning up that code here a bit,
because that is definitely not the code we wanna write
to achieve this behavior.
So what's problematic about this code?
Well, we have a lot of repetition
and we have a lot of code in general just to handle this,
and it just doesn't feel
like the shortest possible way of writing this.
And indeed it isn't.
Now of course, one tiny piece of code we can get rid of
is that code here where I use my input ref.
Because I am using state here to get the value,
there is no need to keep the input ref around,
but that's just a small thing.
I will nonetheless remove it.
But that's not the main thing I wanna change,
though here I will therefore also delete name input ref,
remove to use ref import and down in the JSX code,
remove this ref assignment.
But again, that was not the main thing.
The main thing instead,
is just general validation logic
with all those different event handler functions
and what they're doing.
I think it doesn't have to be that complex.
In the end,
we must not forget that it is all about
finding out whether the input is valid
and if it was touched,
and if it's invalid and was touched,
we wanna show the user an error,
otherwise we don't want to do that.
Since that is the goal,
we actually don't necessarily have to manage
a separate entered name as a valid state,
instead, let me get rid of that dummy use effect call.
We don't need it here,
instead we could add a derived
entered name is valid constant here
and get rid of that state here,
and just work with the value and detached state.
Because entered name is valid
is simply something we can derive
from the entered name state,
and since this entire component function will re-execute
whenever a new value is entered,
we ensure that this constant
will always take into account
the latest value and touched state.
Because whenever one of these two states changes,
this component function gets re-rendered.
So here in entered name is valid,
I wanna store the result of checking entered name.
So this entered name state here.
.trim being equal or not equal to an empty string
because this is entered name is valid
and that should be true if this here yields true.
If the trend entered name is not empty,
then entered name is valid.
This means that we can get rid of all the parts of the code
where we set entered name as valid
because deriving this result
from the already existing states like this is enough,
and here I do set entered name,
hence we ensure that the component function gets re-rendered
and gets reevaluated on every keystroke,
which is exactly what we want here.
Now what about this name input blur handler?
Well, in the end here,
I also don't need to validate this.
Instead, we can delete this
and we can rely on this inferred state
combined with this inferred value down there,
name input is invalid,
which takes this inferred constant into account.
The entered name is valid,
which is based on the entered name value
and combines that with entered name touched.
And to make this a bit easier,
I'll move that constant right below entered name is valid.
So these two lines of code now work together.
We first find out if the entered name was valid
and we then check if it's not valid,
and combine that information with entered name touched.
So now we still get these values,
but we have to manage one state slice less,
we don't have to manage the state validity.
Now, in the form submission handler,
we of course, still wanna keep this if check around though,
to cancel the form submission if the input is invalid,
but here we don't need to set the validity,
instead here we can simply check if entered name is valid
is false.
So this inferred variable, if that's false.
If it's not valid, I wanna return.
I can do this here
because this function,
this form submission function, this handler function
also gets recreated
when the component function is re-evaluated.
So this form submission handler function
will have access to that latest inferred
entered name is valid value here.
And here where it then set entered name is valid to true,
that is also not needed here
because we got all the code related to that,
which we need already in place.
Now, with all of that,
if we give this a try and reload.
If I submit, we still see that it's invalid.
If I click in there and out of there, we see this.
If I enter something, this behaves correctly,
but if I then submit,
if I submit a correct value,
it jumps back to showing me that this is invalid,
and that's not a bug,
but simply a result from the code we wrote here,
where we set entered name to an empty string
and that indeed does result in entered name being not valid.
But the fix is simple.
We just also wanna reset the touched state
once we submit the form.
So after a set entered name
and setting this back to an empty string,
I want to set set entered name touched back to false
to reset the touched state,
because once the form is submitted,
it of course, should again
act as if it wasn't touched at all
because it's a brand new form now in the end.
So if we add this and then go back.
Now, if I submit this form,
it's not showing me the error again.
And we now definitely slimmed down that code
and have a way more readable and manageable code.
And I know that it took quite a lot of steps to get there,
but I wanted to make it clear
what the thought process is here
and why we are doing it like that.
And let me get rid of that use effect import,
which we don't need anymore.
With that, we have a relatively lean component here,
which manages the input value and the touched state,
and then derives to validity from those states.