Would you like to inspect the original subtitles? These are the user uploaded subtitles that are being translated:
1
00:00:02,110 --> 00:00:03,090
So with that, we know
2
00:00:03,090 --> 00:00:05,530
when we might wanna use useReducer,
3
00:00:05,530 --> 00:00:06,773
how does it work though?
4
00:00:08,260 --> 00:00:10,760
It looks like this, and that's quite a bit of code.
5
00:00:10,760 --> 00:00:14,710
So let's have a look at this step by step.
6
00:00:14,710 --> 00:00:16,960
useReducer just like useState,
7
00:00:16,960 --> 00:00:20,910
always returns an array with exactly two values.
8
00:00:20,910 --> 00:00:23,810
And therefore you can use array destructuring
9
00:00:23,810 --> 00:00:27,380
as we did it with useState to pull out these values
10
00:00:27,380 --> 00:00:30,010
and store them in separate constants.
11
00:00:30,010 --> 00:00:32,220
Now, the two values you are getting
12
00:00:32,220 --> 00:00:34,660
are the latest state snapshot,
13
00:00:34,660 --> 00:00:37,080
because it is a state management mechanism
14
00:00:37,080 --> 00:00:38,120
like useState.
15
00:00:38,120 --> 00:00:40,453
So of course you get your state snapshot.
16
00:00:41,440 --> 00:00:42,890
But you also get a function
17
00:00:42,890 --> 00:00:46,190
that allows you to update that state snapshot.
18
00:00:46,190 --> 00:00:50,860
So that's kind of the same as for useState,
19
00:00:50,860 --> 00:00:54,800
though the state updating function will work differently.
20
00:00:54,800 --> 00:00:57,630
Instead of just setting a new state value,
21
00:00:57,630 --> 00:01:01,430
you will dispatch an action.
22
00:01:01,430 --> 00:01:04,950
And that action will be consumed by the first argument
23
00:01:04,950 --> 00:01:08,963
you pass to useReducer a so-called reducer function.
24
00:01:09,880 --> 00:01:11,220
So this is a function
25
00:01:11,220 --> 00:01:15,430
which gets the latest state snapshot automatically
26
00:01:15,430 --> 00:01:18,310
because this function will be called by React
27
00:01:18,310 --> 00:01:21,390
and it gets the action that was dispatched.
28
00:01:21,390 --> 00:01:24,380
Because React will call this reducer function
29
00:01:24,380 --> 00:01:26,990
whenever a new action is dispatched.
30
00:01:26,990 --> 00:01:31,000
So then it gets the last state snapshot managed by React.
31
00:01:31,000 --> 00:01:33,410
And that gets the action that was dispatched
32
00:01:33,410 --> 00:01:36,723
that triggered this reducer function execution.
33
00:01:38,070 --> 00:01:39,580
Now the reducer function
34
00:01:39,580 --> 00:01:41,760
then also should do one important thing.
35
00:01:41,760 --> 00:01:45,880
It should return a new updated state.
36
00:01:45,880 --> 00:01:50,050
So it's a bit like the function form of the useState hook,
37
00:01:50,050 --> 00:01:52,470
but an extended version of that, you could say,
38
00:01:52,470 --> 00:01:56,180
because of that action thing, which you'll see in action,
39
00:01:56,180 --> 00:01:58,043
no pun intended, in a second.
40
00:01:59,070 --> 00:02:01,320
In addition, you can also set some initial state
41
00:02:01,320 --> 00:02:04,280
and also an initial function
42
00:02:04,280 --> 00:02:06,470
that should run to set the initial state
43
00:02:06,470 --> 00:02:09,139
in case your initial state is a bit more complex.
44
00:02:09,139 --> 00:02:13,250
And for example, the result of let's say HTTP requests
45
00:02:13,250 --> 00:02:14,580
or anything like that.
46
00:02:14,580 --> 00:02:16,280
We'll ignore that for now.
47
00:02:16,280 --> 00:02:18,240
So that's useReducer in theory.
48
00:02:18,240 --> 00:02:19,390
Let's see it in action.
49
00:02:20,250 --> 00:02:24,570
Now I did mention that we could use useReducer here
50
00:02:24,570 --> 00:02:28,420
to combine our entered values and validities
51
00:02:28,420 --> 00:02:31,050
for the email and the password.
52
00:02:31,050 --> 00:02:33,320
And we could also use it to manage
53
00:02:33,320 --> 00:02:36,290
the overall form state with it.
54
00:02:36,290 --> 00:02:39,330
So we could either manage one big form state
55
00:02:39,330 --> 00:02:43,410
that includes everything or in multiple smaller states.
56
00:02:43,410 --> 00:02:46,340
Both would work, both would be fine,
57
00:02:46,340 --> 00:02:48,820
but to keep things simple here,
58
00:02:48,820 --> 00:02:52,590
we will simply start by managing our emailState
59
00:02:52,590 --> 00:02:54,673
with useReducer.
60
00:02:54,673 --> 00:02:57,550
And desired goal is to combine the value
61
00:02:57,550 --> 00:03:01,963
and the validity into one state managed by useReducer.
62
00:03:03,800 --> 00:03:08,163
First of all, we need to import useReducer here.
63
00:03:10,090 --> 00:03:12,970
And we then call it for example here.
64
00:03:12,970 --> 00:03:16,040
And useReducer, as you learned returns an array
65
00:03:16,040 --> 00:03:17,490
with exactly two elements,
66
00:03:17,490 --> 00:03:19,060
and we can use array destructuring
67
00:03:19,060 --> 00:03:20,743
to pull those elements out of it.
68
00:03:21,750 --> 00:03:24,260
Now I'm going to useReducer for my email
69
00:03:24,260 --> 00:03:25,930
and my password separately.
70
00:03:25,930 --> 00:03:28,950
You could also merge this all into one big reducer
71
00:03:28,950 --> 00:03:30,790
and here we therefore get back,
72
00:03:30,790 --> 00:03:34,790
let's say the emailState and our dispatch function.
73
00:03:34,790 --> 00:03:36,623
I'll name it, dispatchEmail.
74
00:03:37,860 --> 00:03:39,773
These names are up to you, of course.
75
00:03:41,030 --> 00:03:44,030
Then I mentioned that useReducer as a first argument
76
00:03:44,030 --> 00:03:45,470
takes a function.
77
00:03:45,470 --> 00:03:48,160
Here again, I'm using an anonymous function.
78
00:03:48,160 --> 00:03:50,530
Though we actually could also outsource this
79
00:03:50,530 --> 00:03:52,460
into a separate named function,
80
00:03:52,460 --> 00:03:54,850
maybe to make this easier to read.
81
00:03:54,850 --> 00:03:56,653
And I'll name this emailReducer
82
00:03:57,840 --> 00:03:59,700
and I'll store my function,
83
00:03:59,700 --> 00:04:01,850
my arrow function in this constant
84
00:04:01,850 --> 00:04:04,333
so that I can point at email reducer here.
85
00:04:05,200 --> 00:04:09,440
Now, please note that I created this reducer function
86
00:04:09,440 --> 00:04:12,070
outside of the component function.
87
00:04:12,070 --> 00:04:16,750
And I did so because inside of this reducer function,
88
00:04:16,750 --> 00:04:18,519
we won't need any data
89
00:04:18,519 --> 00:04:21,630
that's generated inside of the component function.
90
00:04:21,630 --> 00:04:26,630
So this reducer function can be created outside of the scope
91
00:04:27,080 --> 00:04:28,970
of this component function
92
00:04:28,970 --> 00:04:32,250
because it doesn't need to interact with anything
93
00:04:32,250 --> 00:04:35,430
defined inside of the component function.
94
00:04:35,430 --> 00:04:38,230
All the data which will be required
95
00:04:38,230 --> 00:04:41,320
and used inside of the reducer function
96
00:04:41,320 --> 00:04:44,180
will be passed into this function
97
00:04:44,180 --> 00:04:48,180
when it's executed by React, automatically.
98
00:04:48,180 --> 00:04:50,220
So that's why we can define it
99
00:04:50,220 --> 00:04:53,100
outside off the component function here.
100
00:04:53,100 --> 00:04:56,120
Now this reducer function receives two arguments,
101
00:04:56,120 --> 00:04:57,470
two parameters.
102
00:04:57,470 --> 00:05:02,470
Our last state snapshot and the action that was dispatched.
103
00:05:03,210 --> 00:05:06,730
And you'll see what this action is in just a second.
104
00:05:06,730 --> 00:05:08,900
And we should return a new state.
105
00:05:08,900 --> 00:05:11,510
Now here, our state could be an object
106
00:05:11,510 --> 00:05:14,860
where we have the value, which is initially an empty string.
107
00:05:14,860 --> 00:05:18,040
And let's say the isValid field, which initially is false,
108
00:05:18,040 --> 00:05:18,913
for example.
109
00:05:20,660 --> 00:05:22,830
That also could be our initial state here
110
00:05:22,830 --> 00:05:24,160
which is the second argument
111
00:05:24,160 --> 00:05:29,040
we passed to useReducer value and isValid to false.
112
00:05:29,040 --> 00:05:31,100
That's the initial state we set here
113
00:05:31,100 --> 00:05:32,993
for our emailState snapshot.
114
00:05:34,600 --> 00:05:38,633
Now the emailState is therefore what we can use in our code.
115
00:05:41,070 --> 00:05:44,980
For example here, where I want the entered email.
116
00:05:44,980 --> 00:05:47,290
Now that's emailState.value
117
00:05:47,290 --> 00:05:49,700
because that's where we're going to store it.
118
00:05:49,700 --> 00:05:51,290
The entered value.
119
00:05:51,290 --> 00:05:54,790
We don't have to code for that yet, but soon we will.
120
00:05:54,790 --> 00:05:56,820
So that's where we could access this.
121
00:05:56,820 --> 00:06:01,210
Also here, emailState.value.includes('@').
122
00:06:01,210 --> 00:06:02,840
But actually keep in mind
123
00:06:02,840 --> 00:06:05,770
that we have the isValid field in there
124
00:06:05,770 --> 00:06:09,400
and we're going to add code that changes it eventually soon.
125
00:06:09,400 --> 00:06:12,490
So instead of revalidating here,
126
00:06:12,490 --> 00:06:17,300
we could also just check if emailState isValid is true,
127
00:06:17,300 --> 00:06:19,774
and therefore we can simplify this here,
128
00:06:19,774 --> 00:06:23,386
emailState isValid.
129
00:06:23,386 --> 00:06:25,820
And if we scroll down further here in the submit handler,
130
00:06:25,820 --> 00:06:28,150
here we wanna forward the value.
131
00:06:28,150 --> 00:06:31,283
So that would be emailState.value.
132
00:06:32,800 --> 00:06:35,083
And then the JSX code, of course,
133
00:06:36,100 --> 00:06:38,190
instead of email isValid,
134
00:06:38,190 --> 00:06:40,733
we have emailState isValid.
135
00:06:43,180 --> 00:06:46,830
And here where I pass the value back into the input,
136
00:06:46,830 --> 00:06:48,843
we have emailState.value,
137
00:06:51,421 --> 00:06:53,910
and that should be the different places
138
00:06:53,910 --> 00:06:56,463
where I'm using my email states.
139
00:06:57,360 --> 00:07:00,970
With that, entered email and email isValid
140
00:07:00,970 --> 00:07:02,900
should now be gray because we're not using them
141
00:07:02,900 --> 00:07:04,830
anywhere in our code anymore.
142
00:07:04,830 --> 00:07:07,570
So we can remove these to useState calls here,
143
00:07:07,570 --> 00:07:08,840
and I will comment them out
144
00:07:08,840 --> 00:07:10,620
so that we still see this alternative,
145
00:07:10,620 --> 00:07:12,720
but we're not using it anymore.
146
00:07:12,720 --> 00:07:14,330
But we're not done with the reducer.
147
00:07:14,330 --> 00:07:16,590
Right now, it always returns to this state,
148
00:07:16,590 --> 00:07:18,390
which of course is not what we want.
149
00:07:19,370 --> 00:07:22,510
Instead, we need to dispatch an action eventually.
150
00:07:22,510 --> 00:07:24,730
We need to dispatch it here, for example,
151
00:07:24,730 --> 00:07:26,830
when we want to update the value,
152
00:07:26,830 --> 00:07:29,833
or here, when we want to update the validity.
153
00:07:31,140 --> 00:07:32,820
Now let's start with the value.
154
00:07:32,820 --> 00:07:36,270
Here we now update this by calling dispatchEmail
155
00:07:36,270 --> 00:07:39,070
and we pass to it as so-called action.
156
00:07:39,070 --> 00:07:41,220
Now it's totally up to you
157
00:07:41,220 --> 00:07:43,060
what this action is.
158
00:07:43,060 --> 00:07:44,950
It can be a string identifier,
159
00:07:44,950 --> 00:07:47,297
something like NEW_EMAIL_VALUE.
160
00:07:49,739 --> 00:07:51,090
It could be a number,
161
00:07:51,090 --> 00:07:53,260
but often will be an object
162
00:07:53,260 --> 00:07:56,870
which has some field that holds some identifier
163
00:07:56,870 --> 00:07:59,540
often the field is then named type.
164
00:07:59,540 --> 00:08:04,540
And that could be something like USER_INPUT, for example.
165
00:08:04,800 --> 00:08:06,690
Now it doesn't have to be all caps.
166
00:08:06,690 --> 00:08:09,110
That's just a convention you see a lot.
167
00:08:09,110 --> 00:08:10,620
So a string, all caps,
168
00:08:10,620 --> 00:08:14,710
with some clearly understandable identifier.
169
00:08:14,710 --> 00:08:19,290
And then we also can add an extra payload to this action.
170
00:08:19,290 --> 00:08:22,200
Again, I'm saying you can, because it's up to you,
171
00:08:22,200 --> 00:08:24,853
but here, since we wanna save what the user entered,
172
00:08:25,900 --> 00:08:28,350
it would make sense to add some payload.
173
00:08:28,350 --> 00:08:30,430
So for example, a val field
174
00:08:30,430 --> 00:08:33,673
that holds the event target value.
175
00:08:34,559 --> 00:08:35,960
So now that's our action.
176
00:08:35,960 --> 00:08:38,690
It's this object with a type field
177
00:08:38,690 --> 00:08:43,070
that describes what happened and extra payload in this case,
178
00:08:43,070 --> 00:08:44,733
the value the user entered.
179
00:08:48,510 --> 00:08:52,070
So this now will trigger this function here to execute
180
00:08:52,070 --> 00:08:55,880
because that's the reducer function we passed to useReducer.
181
00:08:56,850 --> 00:08:58,610
Now here we can handle this action,
182
00:08:58,610 --> 00:09:00,670
for example, with the if statement.
183
00:09:00,670 --> 00:09:04,563
We can check if action.type is equal to user input.
184
00:09:05,710 --> 00:09:10,110
Keep in mind, what we dispatch as action will be an object
185
00:09:10,110 --> 00:09:12,233
because that's what we set it to here.
186
00:09:13,200 --> 00:09:16,050
And this object happens to have a type field
187
00:09:16,050 --> 00:09:18,560
so I can check for action.type here
188
00:09:18,560 --> 00:09:21,610
and check if the values stored in that type field
189
00:09:21,610 --> 00:09:24,433
is that string with the content user input.
190
00:09:25,290 --> 00:09:27,030
And if that's the case, we could say,
191
00:09:27,030 --> 00:09:31,350
now then I don't want to return this empty state snapshot.
192
00:09:31,350 --> 00:09:35,420
Instead, I want to return the state snapshot for my email,
193
00:09:35,420 --> 00:09:38,490
where the value is action.val.
194
00:09:38,490 --> 00:09:41,463
That's the payload we appended to our action.
195
00:09:42,550 --> 00:09:45,230
And maybe we also want to update the validity here,
196
00:09:45,230 --> 00:09:46,820
if we're already added.
197
00:09:46,820 --> 00:09:49,683
Simply by, for example, checking if action valid,
198
00:09:51,710 --> 00:09:53,660
and then the same logic as down there,
199
00:09:53,660 --> 00:09:57,890
includes the @ symbol for this very trivial validation.
200
00:09:57,890 --> 00:10:00,970
So here I'm then updating both the value
201
00:10:00,970 --> 00:10:05,490
and isValid whenever I received as user input action.
202
00:10:05,490 --> 00:10:09,000
And for any other action that might reach this reducer,
203
00:10:09,000 --> 00:10:10,843
this default state will be returned.
204
00:10:12,860 --> 00:10:15,800
Now we also need to dispatch an action here
205
00:10:15,800 --> 00:10:17,573
on the validate email handler.
206
00:10:18,500 --> 00:10:21,330
So instead of setting the email as valid here,
207
00:10:21,330 --> 00:10:22,713
I can dispatch,
208
00:10:25,100 --> 00:10:26,390
email again.
209
00:10:26,390 --> 00:10:28,070
Again, passing an object.
210
00:10:28,070 --> 00:10:29,590
You should be consistent.
211
00:10:29,590 --> 00:10:32,480
Your actions should always have the same structure,
212
00:10:32,480 --> 00:10:33,940
so that your code, where you,
213
00:10:33,940 --> 00:10:36,970
for example, try to access a type property
214
00:10:36,970 --> 00:10:38,960
does not suddenly fail.
215
00:10:38,960 --> 00:10:41,650
So once you've decided for an action structure,
216
00:10:41,650 --> 00:10:43,440
you wanna stick to it.
217
00:10:43,440 --> 00:10:46,530
Therefore, here I, again, dispatch an object
218
00:10:46,530 --> 00:10:47,820
with a type field.
219
00:10:47,820 --> 00:10:49,630
Now here it's for example,
220
00:10:49,630 --> 00:10:53,350
input blur, because the input lost focus,
221
00:10:53,350 --> 00:10:54,423
it was blurred.
222
00:10:55,690 --> 00:10:58,770
And we don't need to add a value here necessarily
223
00:10:58,770 --> 00:11:01,080
because all we care about here
224
00:11:01,080 --> 00:11:03,300
is that the input lost focus.
225
00:11:03,300 --> 00:11:06,270
There is no extra data that needs to be added.
226
00:11:06,270 --> 00:11:08,630
So here we have a simpler action.
227
00:11:08,630 --> 00:11:11,800
So still an object, still with a type property,
228
00:11:11,800 --> 00:11:13,083
but without a value.
229
00:11:14,240 --> 00:11:16,980
The fact that the val is missing does not matter
230
00:11:16,980 --> 00:11:18,880
because this line here,
231
00:11:18,880 --> 00:11:20,760
where we try to access the value,
232
00:11:20,760 --> 00:11:25,543
will not run for action of type input blur.
233
00:11:26,380 --> 00:11:29,403
Because we only run this if the action type is user input.
234
00:11:31,500 --> 00:11:36,093
Instead I will check if the action type is input blur.
235
00:11:37,220 --> 00:11:42,070
And if it is, I wanna return a new snapshot,
236
00:11:42,070 --> 00:11:44,700
a new state value for my emailState.
237
00:11:44,700 --> 00:11:46,300
But now the value of course
238
00:11:46,300 --> 00:11:48,570
should be the value we had before.
239
00:11:48,570 --> 00:11:50,670
I don't wanna reset this to be empty
240
00:11:50,670 --> 00:11:52,890
because the input could blur
241
00:11:52,890 --> 00:11:54,290
after the user entered something.
242
00:11:54,290 --> 00:11:56,120
I don't wanna lose that.
243
00:11:56,120 --> 00:11:58,820
So therefore I'll use my last state snapshot,
244
00:11:58,820 --> 00:12:00,030
which I get here.
245
00:12:00,030 --> 00:12:01,610
And that this is guaranteed
246
00:12:01,610 --> 00:12:04,770
to be the absolute last state snapshot.
247
00:12:04,770 --> 00:12:06,910
React gives us this state snapshot
248
00:12:06,910 --> 00:12:09,060
and it makes sure that it's the latest one.
249
00:12:09,900 --> 00:12:13,770
So here we can safely access state.value, for example,
250
00:12:13,770 --> 00:12:17,400
to access the last value that was entered for the email.
251
00:12:17,400 --> 00:12:19,210
And for the validity, we can there for check
252
00:12:19,210 --> 00:12:21,710
if the state value is valid,
253
00:12:21,710 --> 00:12:24,783
by again, repeating our validity check here.
254
00:12:25,760 --> 00:12:27,940
And of course you could always refactor this check
255
00:12:27,940 --> 00:12:29,100
into a function,
256
00:12:29,100 --> 00:12:31,713
but I don't want to make this overly complicated.
257
00:12:32,720 --> 00:12:35,330
So with this, we now have this extra action.
258
00:12:35,330 --> 00:12:38,740
And as a result, if I log out here,
259
00:12:38,740 --> 00:12:43,330
you see initially it's blurred, which makes sense actually,
260
00:12:43,330 --> 00:12:48,330
because my initial value for isValid is false.
261
00:12:48,620 --> 00:12:51,713
If I set this to undefined or to null instead,
262
00:12:52,840 --> 00:12:55,000
you'll see it's not treated as invalid.
263
00:12:55,000 --> 00:12:58,740
It's not treated as if it was blurred from the beginning on.
264
00:12:58,740 --> 00:13:00,410
But if I click in there it is.
265
00:13:00,410 --> 00:13:04,310
And if I then start typing, I'm getting an error.
266
00:13:04,310 --> 00:13:07,290
Cannot read property 'includes' of undefined.
267
00:13:07,290 --> 00:13:08,840
And what could be causing that?
268
00:13:10,440 --> 00:13:13,040
Well, it looks like we're having problems
269
00:13:13,040 --> 00:13:14,770
running this code here,
270
00:13:14,770 --> 00:13:18,510
because that clearly has to be the action that triggered.
271
00:13:18,510 --> 00:13:21,540
And that's simply because here I'm checking action.valid.
272
00:13:21,540 --> 00:13:23,970
Of course it should be action.val.
273
00:13:23,970 --> 00:13:26,150
So the value I'm retrieving here.
274
00:13:26,150 --> 00:13:28,820
So a simple typo here, my mistake.
275
00:13:28,820 --> 00:13:29,850
Let's reload.
276
00:13:29,850 --> 00:13:31,170
Now I can type here.
277
00:13:31,170 --> 00:13:32,470
And then that all seems to work.
278
00:13:32,470 --> 00:13:36,030
And overall, this works as before,
279
00:13:36,030 --> 00:13:39,130
without the debouncing, because I commented out that code,
280
00:13:39,130 --> 00:13:41,590
but the general form validation works,
281
00:13:41,590 --> 00:13:43,343
now with the help of useReducer.
282
00:13:44,280 --> 00:13:47,290
And this allows us to group this emailState together
283
00:13:47,290 --> 00:13:50,070
and manage it in one place.
284
00:13:50,070 --> 00:13:52,550
It's a little bit more set up up here,
285
00:13:52,550 --> 00:13:54,650
but on the other hand, the code in the component
286
00:13:54,650 --> 00:13:58,050
then is simpler because there, we only need to dispatch
287
00:13:58,050 --> 00:14:01,263
and not do any validation or anything like that.
288
00:14:02,350 --> 00:14:04,590
So here's a task for you now.
289
00:14:04,590 --> 00:14:05,677
Take this.
290
00:14:05,677 --> 00:14:07,990
How do you find the finish code snapshot,
291
00:14:07,990 --> 00:14:10,323
and do the same for the password.
22789
Can't find what you're looking for?
Get subtitles in any language from opensubtitles.com, and translate them here.