1
00:00:03,000 --> 00:00:06,632
The SignInPage is now using a React Query mutation

2
00:00:06,632 --> 00:00:08,157
to perform the login,

3
00:00:08,157 --> 00:00:10,483
and it's using the "queryClient"

4
00:00:10,483 --> 00:00:13,316
to update the "user" data in the cache.

5
00:00:13,316 --> 00:00:16,803
What I'd like to do now is extract a custom hook

6
00:00:16,803 --> 00:00:19,346
to encapsulated this functionality,

7
00:00:20,210 --> 00:00:22,859
just like we did for the user query,

8
00:00:22,859 --> 00:00:25,434
when we created the "useUser" hook.

9
00:00:26,008 --> 00:00:28,181
So let's create another hook function,

10
00:00:29,974 --> 00:00:32,481
and I'll call this one "useSignIn".

11
00:00:32,981 --> 00:00:34,788
In the body of this function

12
00:00:34,788 --> 00:00:37,628
we want to move the code from the SignInPage

13
00:00:37,628 --> 00:00:39,435
where we call "useMutation".

14
00:00:40,064 --> 00:00:42,120
But here we have a small problem:

15
00:00:42,120 --> 00:00:44,052
in the mutation function we use

16
00:00:44,052 --> 00:00:46,357
the "email" and "password" variables.

17
00:00:46,981 --> 00:00:49,772
And these are state variables we define above.

18
00:00:50,272 --> 00:00:53,328
So we cannot simply move the "useMutation" code

19
00:00:53,328 --> 00:00:55,149
to a different file, because

20
00:00:55,149 --> 00:00:58,464
"email" and "password" wouldn't be available there.

21
00:00:59,094 --> 00:01:01,363
Thankfully this is easy to solve.

22
00:01:01,363 --> 00:01:03,150
When we call "mutateAsync"

23
00:01:03,150 --> 00:01:05,144
to actually send the request,

24
00:01:05,781 --> 00:01:07,605
we can pass an argument to it

25
00:01:07,605 --> 00:01:09,681
containing any variables we want,

26
00:01:10,243 --> 00:01:12,801
and React Query will pass that argument

27
00:01:12,801 --> 00:01:14,440
to our mutation function.

28
00:01:15,006 --> 00:01:17,014
So we can use this feature to pass

29
00:01:17,014 --> 00:01:19,258
an object with "email" and "password",

30
00:01:19,971 --> 00:01:22,717
and then in the mutation function we can

31
00:01:22,717 --> 00:01:25,050
destructure those same properties.

32
00:01:25,618 --> 00:01:27,730
Let me just put this on a separate line

33
00:01:27,730 --> 00:01:29,842
otherwise it doesn't fit on the screen.

34
00:01:30,397 --> 00:01:33,471
So this way the mutation function is no longer

35
00:01:33,471 --> 00:01:36,947
using the "email" and "password" variables directly.

36
00:01:37,514 --> 00:01:39,796
This means we can now move this code

37
00:01:39,796 --> 00:01:40,810
to the new hook.

38
00:01:42,747 --> 00:01:44,816
And notice that I also copied

39
00:01:44,816 --> 00:01:46,671
the "useQueryClient" line,

40
00:01:46,671 --> 00:01:49,239
because we'll need the "queryClient"

41
00:01:49,239 --> 00:01:52,307
to update the "user" data after we sign in.

42
00:01:53,022 --> 00:01:54,828
Now, an interesting question is:

43
00:01:54,828 --> 00:01:57,143
what should we return from this function?

44
00:01:57,700 --> 00:02:00,076
Well, that depends on what we need

45
00:02:00,076 --> 00:02:02,593
where we're going to call that hook.

46
00:02:03,163 --> 00:02:05,220
In the SignInPage we trigger

47
00:02:05,220 --> 00:02:07,278
the login request on submit,

48
00:02:07,278 --> 00:02:10,365
so our hook will need to return a function

49
00:02:10,365 --> 00:02:13,452
that we can call here, like "mutateAsync".

50
00:02:14,173 --> 00:02:16,514
But that's not the only thing, because

51
00:02:17,139 --> 00:02:20,799
we're also using the "isError" and "isLoading" flags.

52
00:02:21,299 --> 00:02:23,645
So that's something else we'll need to return

53
00:02:23,645 --> 00:02:24,740
from our custom hook,

54
00:02:25,293 --> 00:02:27,354
if we want to be able to replace

55
00:02:27,354 --> 00:02:29,673
the existing code in the SignInPage.

56
00:02:30,237 --> 00:02:32,202
Since we need more than one thing

57
00:02:32,202 --> 00:02:33,631
we can return an object,

58
00:02:33,631 --> 00:02:35,833
where we can put multiple properties.

59
00:02:36,453 --> 00:02:39,060
Let's start with the "error" and "loading" flags.

60
00:02:39,560 --> 00:02:42,190
We can return a "signInError" property

61
00:02:42,190 --> 00:02:45,373
that's simply the value of "mutation.isError".

62
00:02:45,943 --> 00:02:49,317
Likewise we can have a "signInLoading" property,

63
00:02:49,317 --> 00:02:52,058
with the value of "mutation.isLoading".

64
00:02:52,629 --> 00:02:54,298
I called "signInError",

65
00:02:54,298 --> 00:02:56,838
rather than just "isError", because

66
00:02:56,838 --> 00:02:59,305
this way it will be easier to tell

67
00:02:59,305 --> 00:03:02,353
that it's ​related to the sign in request.

68
00:03:03,071 --> 00:03:05,178
In fact, let's go to the SignInPage

69
00:03:05,678 --> 00:03:07,929
and start replacing the old code

70
00:03:07,929 --> 00:03:10,040
with our new "useSignIn" hook,

71
00:03:10,040 --> 00:03:12,221
that should have been imported.

72
00:03:13,278 --> 00:03:15,165
"useSignIn" returns an object,

73
00:03:15,165 --> 00:03:16,675
that we can destructure,

74
00:03:17,238 --> 00:03:19,187
extracting the "signInError"

75
00:03:19,187 --> 00:03:21,346
and "signInLoading" properties.

76
00:03:21,916 --> 00:03:24,549
At this point we can use "signInError"

77
00:03:24,549 --> 00:03:26,628
instead of "mutation.isError",

78
00:03:27,198 --> 00:03:29,986
and also replace "mutation.isLoading"

79
00:03:29,986 --> 00:03:31,568
with "signInLoading".

80
00:03:32,144 --> 00:03:35,889
Ok. This takes care of the request status flags.

81
00:03:36,389 --> 00:03:38,423
Now it's time to think about

82
00:03:38,423 --> 00:03:41,329
how to actually execute the API request.

83
00:03:41,902 --> 00:03:43,561
We'll still need to call

84
00:03:43,561 --> 00:03:46,880
"mutateAsync" and then "setQueryData" somewhere,

85
00:03:47,450 --> 00:03:49,958
so let's copy this code into our custom hook.

86
00:03:50,816 --> 00:03:54,175
But from here we could return a single function

87
00:03:54,175 --> 00:03:55,891
that I'll call "signIn".

88
00:03:57,049 --> 00:04:00,199
This will take care of calling "mutateAsync"

89
00:04:00,199 --> 00:04:01,559
and "setQueryData".

90
00:04:02,131 --> 00:04:03,839
So where we use this hook

91
00:04:03,839 --> 00:04:06,437
we'll be able to simply call "signIn",

92
00:04:06,437 --> 00:04:08,419
without having to worry about

93
00:04:08,419 --> 00:04:11,290
separately updating the React Query cache.

94
00:04:11,290 --> 00:04:14,297
However, we are using the email and password

95
00:04:14,297 --> 00:04:16,142
when calling "mutateAsync",

96
00:04:16,985 --> 00:04:19,377
so we'll need to pass those variables

97
00:04:19,377 --> 00:04:21,382
as parameters to this function.

98
00:04:21,947 --> 00:04:24,471
Ok. Let's save and see if this could work.

99
00:04:26,780 --> 00:04:30,223
"useSignIn" now also returns a "signIn" function.

100
00:04:30,723 --> 00:04:32,568
And we want to call that function

101
00:04:32,568 --> 00:04:33,910
instead of the old code,

102
00:04:35,189 --> 00:04:38,197
passing "email" and "password" as arguments.

103
00:04:38,697 --> 00:04:41,655
"signIn" is async, so we need to await it.

104
00:04:42,155 --> 00:04:45,067
And we used to log the "user" data here,

105
00:04:45,067 --> 00:04:49,000
but our new "signIn" function doesn't return anything.

106
00:04:49,573 --> 00:04:52,816
That's fine, we don't really need the user here.

107
00:04:52,816 --> 00:04:55,384
We can simply remove this log message.

108
00:04:55,384 --> 00:04:58,561
So, like this, "signIn" doesn't return anything

109
00:04:58,561 --> 00:05:01,061
but we still wait for it to complete,

110
00:05:01,061 --> 00:05:03,224
because it could throw an error,

111
00:05:03,224 --> 00:05:06,738
and in that case we don't want to call "router.push"

112
00:05:06,738 --> 00:05:08,968
to send the user to the HomePage.

113
00:05:09,874 --> 00:05:11,670
Maybe it would actually be nicer

114
00:05:11,670 --> 00:05:14,196
not to have a "try" and "catch" in this case.

115
00:05:14,753 --> 00:05:16,979
What if we return a boolean value

116
00:05:16,979 --> 00:05:18,801
from our "signIn" function,

117
00:05:18,801 --> 00:05:21,703
telling if the login was successful or not?

118
00:05:22,338 --> 00:05:24,244
We could do the "try" and "catch" here.

119
00:05:26,104 --> 00:05:28,914
"mutateAsync" can still throw an error of course.

120
00:05:31,037 --> 00:05:34,347
But if everything succeeds we can return "true",

121
00:05:34,847 --> 00:05:37,688
while if there's an error we can return "false".

122
00:05:38,188 --> 00:05:40,234
Since we're writing a custom hook

123
00:05:40,234 --> 00:05:42,033
we can tailor what it returns

124
00:05:42,033 --> 00:05:44,947
to make it easier to use for our specific case.

125
00:05:45,572 --> 00:05:47,283
So here in the SignInPage

126
00:05:47,283 --> 00:05:49,748
we can remove the "try" and "catch".

127
00:05:50,317 --> 00:05:53,238
Instead we get a boolean value from "signIn",

128
00:05:53,238 --> 00:05:54,732
that I'll call "valid",

129
00:05:55,297 --> 00:05:57,802
and only if the "signIn" was "valid"

130
00:05:57,802 --> 00:06:00,307
then we'll redirect to the HomePage.

131
00:06:00,877 --> 00:06:03,453
I think like this our code is more readable.

132
00:06:03,953 --> 00:06:05,729
But we haven't actually tested

133
00:06:05,729 --> 00:06:08,038
if all the changes we made are working.

134
00:06:09,719 --> 00:06:11,374
So let's try signing in again,

135
00:06:12,185 --> 00:06:15,487
and let's check the "Invalid credentials" case first.

136
00:06:15,487 --> 00:06:17,169
This is still working fine.

137
00:06:17,732 --> 00:06:19,805
Let's try with a valid password,

138
00:06:20,305 --> 00:06:22,286
and this also works correctly.

139
00:06:22,286 --> 00:06:24,069
We're sent to the HomePage,

140
00:06:24,069 --> 00:06:26,842
and the NavBar shows that we're signed in.

141
00:06:27,475 --> 00:06:29,683
Ok. So I think this is it.

142
00:06:30,183 --> 00:06:32,416
Actually, we should check if there are

143
00:06:32,416 --> 00:06:33,533
any unused imports.

144
00:06:34,092 --> 00:06:37,334
We're not using the React Query hooks here any more.

145
00:06:37,834 --> 00:06:40,477
In fact, we can remove "fetchJson" as well.

146
00:06:40,977 --> 00:06:44,262
That's good, because it shows that in this file

147
00:06:44,262 --> 00:06:46,849
we no longer have any code that deals

148
00:06:46,849 --> 00:06:49,436
directly with making the API request.

149
00:06:49,436 --> 00:06:51,953
We simply call our "useSignIn" hook,

150
00:06:51,953 --> 00:06:55,029
that returns a "signIn" function, and that's

151
00:06:55,029 --> 00:06:58,105
what we call when the user submits the form.

152
00:06:58,955 --> 00:07:01,813
All the logic to make the API request

153
00:07:01,813 --> 00:07:04,517
and deal with the React Query cache

154
00:07:04,517 --> 00:07:08,225
is nicely encapsulated into our new custom hook.

