Afrikaans
Akan
Albanian
Amharic
Arabic
Armenian
Azerbaijani
Basque
Belarusian
Bemba
Bengali
Bihari
Bosnian
Breton
Bulgarian
Cambodian
Catalan
Cebuano
Cherokee
Chichewa
Chinese (Simplified)
Chinese (Traditional)
Corsican
Croatian
Czech
Danish
Dutch
English
Esperanto
Estonian
Ewe
Faroese
Filipino
Finnish
French
Frisian
Ga
Galician
Georgian
German
Greek
Guarani
Gujarati
Haitian Creole
Hausa
Hawaiian
Hebrew
Hindi
Hmong
Hungarian
Icelandic
Igbo
Indonesian
Interlingua
Irish
Italian
Japanese
Javanese
Kannada
Kazakh
Kinyarwanda
Kirundi
Kongo
Korean
Krio (Sierra Leone)
Kurdish
Kurdish (Soranรฎ)
Kyrgyz
Laothian
Latin
Latvian
Lingala
Lithuanian
Lozi
Luganda
Luo
Luxembourgish
Macedonian
Malagasy
Malay
Malayalam
Maltese
Maori
Marathi
Mauritian Creole
Moldavian
Mongolian
Myanmar (Burmese)
Montenegrin
Nepali
Nigerian Pidgin
Northern Sotho
Norwegian
Norwegian (Nynorsk)
Occitan
Oriya
Oromo
Pashto
Polish
Portuguese (Brazil)
Portuguese (Portugal)
Punjabi
Quechua
Romanian
Romansh
Runyakitara
Russian
Samoan
Scots Gaelic
Serbian
Serbo-Croatian
Sesotho
Setswana
Seychellois Creole
Shona
Sindhi
Sinhalese
Slovak
Slovenian
Somali
Spanish
Spanish (Latin American)
Sundanese
Swahili
Swedish
Tajik
Tamil
Tatar
Telugu
Thai
Tigrinya
Tonga
Tshiluba
Tumbuka
Turkish
Turkmen
Twi
Uighur
Ukrainian
Urdu
Uzbek
Vietnamese
Welsh
Wolof
Xhosa
Yiddish
Yoruba
Zulu
So with that, we know
when we might wanna use useReducer,
how does it work though?
It looks like this, and that's quite a bit of code.
So let's have a look at this step by step.
useReducer just like useState,
always returns an array with exactly two values.
And therefore you can use array destructuring
as we did it with useState to pull out these values
and store them in separate constants.
Now, the two values you are getting
are the latest state snapshot,
because it is a state management mechanism
like useState.
So of course you get your state snapshot.
But you also get a function
that allows you to update that state snapshot.
So that's kind of the same as for useState,
though the state updating function will work differently.
Instead of just setting a new state value,
you will dispatch an action.
And that action will be consumed by the first argument
you pass to useReducer a so-called reducer function.
So this is a function
which gets the latest state snapshot automatically
because this function will be called by React
and it gets the action that was dispatched.
Because React will call this reducer function
whenever a new action is dispatched.
So then it gets the last state snapshot managed by React.
And that gets the action that was dispatched
that triggered this reducer function execution.
Now the reducer function
then also should do one important thing.
It should return a new updated state.
So it's a bit like the function form of the useState hook,
but an extended version of that, you could say,
because of that action thing, which you'll see in action,
no pun intended, in a second.
In addition, you can also set some initial state
and also an initial function
that should run to set the initial state
in case your initial state is a bit more complex.
And for example, the result of let's say HTTP requests
or anything like that.
We'll ignore that for now.
So that's useReducer in theory.
Let's see it in action.
Now I did mention that we could use useReducer here
to combine our entered values and validities
for the email and the password.
And we could also use it to manage
the overall form state with it.
So we could either manage one big form state
that includes everything or in multiple smaller states.
Both would work, both would be fine,
but to keep things simple here,
we will simply start by managing our emailState
with useReducer.
And desired goal is to combine the value
and the validity into one state managed by useReducer.
First of all, we need to import useReducer here.
And we then call it for example here.
And useReducer, as you learned returns an array
with exactly two elements,
and we can use array destructuring
to pull those elements out of it.
Now I'm going to useReducer for my email
and my password separately.
You could also merge this all into one big reducer
and here we therefore get back,
let's say the emailState and our dispatch function.
I'll name it, dispatchEmail.
These names are up to you, of course.
Then I mentioned that useReducer as a first argument
takes a function.
Here again, I'm using an anonymous function.
Though we actually could also outsource this
into a separate named function,
maybe to make this easier to read.
And I'll name this emailReducer
and I'll store my function,
my arrow function in this constant
so that I can point at email reducer here.
Now, please note that I created this reducer function
outside of the component function.
And I did so because inside of this reducer function,
we won't need any data
that's generated inside of the component function.
So this reducer function can be created outside of the scope
of this component function
because it doesn't need to interact with anything
defined inside of the component function.
All the data which will be required
and used inside of the reducer function
will be passed into this function
when it's executed by React, automatically.
So that's why we can define it
outside off the component function here.
Now this reducer function receives two arguments,
two parameters.
Our last state snapshot and the action that was dispatched.
And you'll see what this action is in just a second.
And we should return a new state.
Now here, our state could be an object
where we have the value, which is initially an empty string.
And let's say the isValid field, which initially is false,
for example.
That also could be our initial state here
which is the second argument
we passed to useReducer value and isValid to false.
That's the initial state we set here
for our emailState snapshot.
Now the emailState is therefore what we can use in our code.
For example here, where I want the entered email.
Now that's emailState.value
because that's where we're going to store it.
The entered value.
We don't have to code for that yet, but soon we will.
So that's where we could access this.
Also here, emailState.value.includes('@').
But actually keep in mind
that we have the isValid field in there
and we're going to add code that changes it eventually soon.
So instead of revalidating here,
we could also just check if emailState isValid is true,
and therefore we can simplify this here,
emailState isValid.
And if we scroll down further here in the submit handler,
here we wanna forward the value.
So that would be emailState.value.
And then the JSX code, of course,
instead of email isValid,
we have emailState isValid.
And here where I pass the value back into the input,
we have emailState.value,
and that should be the different places
where I'm using my email states.
With that, entered email and email isValid
should now be gray because we're not using them
anywhere in our code anymore.
So we can remove these to useState calls here,
and I will comment them out
so that we still see this alternative,
but we're not using it anymore.
But we're not done with the reducer.
Right now, it always returns to this state,
which of course is not what we want.
Instead, we need to dispatch an action eventually.
We need to dispatch it here, for example,
when we want to update the value,
or here, when we want to update the validity.
Now let's start with the value.
Here we now update this by calling dispatchEmail
and we pass to it as so-called action.
Now it's totally up to you
what this action is.
It can be a string identifier,
something like NEW_EMAIL_VALUE.
It could be a number,
but often will be an object
which has some field that holds some identifier
often the field is then named type.
And that could be something like USER_INPUT, for example.
Now it doesn't have to be all caps.
That's just a convention you see a lot.
So a string, all caps,
with some clearly understandable identifier.
And then we also can add an extra payload to this action.
Again, I'm saying you can, because it's up to you,
but here, since we wanna save what the user entered,
it would make sense to add some payload.
So for example, a val field
that holds the event target value.
So now that's our action.
It's this object with a type field
that describes what happened and extra payload in this case,
the value the user entered.
So this now will trigger this function here to execute
because that's the reducer function we passed to useReducer.
Now here we can handle this action,
for example, with the if statement.
We can check if action.type is equal to user input.
Keep in mind, what we dispatch as action will be an object
because that's what we set it to here.
And this object happens to have a type field
so I can check for action.type here
and check if the values stored in that type field
is that string with the content user input.
And if that's the case, we could say,
now then I don't want to return this empty state snapshot.
Instead, I want to return the state snapshot for my email,
where the value is action.val.
That's the payload we appended to our action.
And maybe we also want to update the validity here,
if we're already added.
Simply by, for example, checking if action valid,
and then the same logic as down there,
includes the @ symbol for this very trivial validation.
So here I'm then updating both the value
and isValid whenever I received as user input action.
And for any other action that might reach this reducer,
this default state will be returned.
Now we also need to dispatch an action here
on the validate email handler.
So instead of setting the email as valid here,
I can dispatch,
email again.
Again, passing an object.
You should be consistent.
Your actions should always have the same structure,
so that your code, where you,
for example, try to access a type property
does not suddenly fail.
So once you've decided for an action structure,
you wanna stick to it.
Therefore, here I, again, dispatch an object
with a type field.
Now here it's for example,
input blur, because the input lost focus,
it was blurred.
And we don't need to add a value here necessarily
because all we care about here
is that the input lost focus.
There is no extra data that needs to be added.
So here we have a simpler action.
So still an object, still with a type property,
but without a value.
The fact that the val is missing does not matter
because this line here,
where we try to access the value,
will not run for action of type input blur.
Because we only run this if the action type is user input.
Instead I will check if the action type is input blur.
And if it is, I wanna return a new snapshot,
a new state value for my emailState.
But now the value of course
should be the value we had before.
I don't wanna reset this to be empty
because the input could blur
after the user entered something.
I don't wanna lose that.
So therefore I'll use my last state snapshot,
which I get here.
And that this is guaranteed
to be the absolute last state snapshot.
React gives us this state snapshot
and it makes sure that it's the latest one.
So here we can safely access state.value, for example,
to access the last value that was entered for the email.
And for the validity, we can there for check
if the state value is valid,
by again, repeating our validity check here.
And of course you could always refactor this check
into a function,
but I don't want to make this overly complicated.
So with this, we now have this extra action.
And as a result, if I log out here,
you see initially it's blurred, which makes sense actually,
because my initial value for isValid is false.
If I set this to undefined or to null instead,
you'll see it's not treated as invalid.
It's not treated as if it was blurred from the beginning on.
But if I click in there it is.
And if I then start typing, I'm getting an error.
Cannot read property 'includes' of undefined.
And what could be causing that?
Well, it looks like we're having problems
running this code here,
because that clearly has to be the action that triggered.
And that's simply because here I'm checking action.valid.
Of course it should be action.val.
So the value I'm retrieving here.
So a simple typo here, my mistake.
Let's reload.
Now I can type here.
And then that all seems to work.
And overall, this works as before,
without the debouncing, because I commented out that code,
but the general form validation works,
now with the help of useReducer.
And this allows us to group this emailState together
and manage it in one place.
It's a little bit more set up up here,
but on the other hand, the code in the component
then is simpler because there, we only need to dispatch
and not do any validation or anything like that.
So here's a task for you now.
Take this.
How do you find the finish code snapshot,
and do the same for the password.
Can't find what you're looking for?
Get subtitles in any language from opensubtitles.com, and translate them here.