1
00:00:00,000 --> 00:00:02,000
Here in this application,

2
00:00:02,000 --> 00:00:05,000
we would provide a better user experience

3
00:00:05,000 --> 00:00:09,000
if we would immediately update this like status

4
00:00:09,000 --> 00:00:13,000
even before it has been processed in the database.

5
00:00:13,000 --> 00:00:16,000
And that's a concept or a pattern

6
00:00:16,000 --> 00:00:18,000
called optimistic updating,

7
00:00:18,000 --> 00:00:22,000
which in the end simply means that we're optimistic

8
00:00:22,000 --> 00:00:25,000
that our update will work, and therefore we wanna show

9
00:00:25,000 --> 00:00:28,000
the new state immediately to the user,

10
00:00:28,000 --> 00:00:31,000
and perform the update behind the scenes.

11
00:00:31,000 --> 00:00:33,000
And then only if that update would fail

12
00:00:33,000 --> 00:00:37,000
or something like this, we wanna roll back the update.

13
00:00:38,000 --> 00:00:43,000
And React and Next.js make that simple and straightforward

14
00:00:43,000 --> 00:00:45,000
because React provides another built-in hook

15
00:00:45,000 --> 00:00:48,000
called useOptimistic, which you can use

16
00:00:48,000 --> 00:00:52,000
to perform such optimistic updates.

17
00:00:52,000 --> 00:00:54,000
And therefore that's a hook we'll use now.

18
00:00:54,000 --> 00:00:58,000
For that, back in this posts.js file

19
00:00:58,000 --> 00:01:00,000
in the components folder,

20
00:01:00,000 --> 00:01:02,000
I wanna update my Posts here,

21
00:01:02,000 --> 00:01:04,000
which I'm outputting optimistically

22
00:01:04,000 --> 00:01:08,000
whenever the data for one of those posts changed.

23
00:01:09,000 --> 00:01:12,000
Now therefore I'll start by calling useOptimistic

24
00:01:14,000 --> 00:01:17,000
from inside this Posts component.

25
00:01:19,000 --> 00:01:22,000
And I'm actually doing this here in the Posts component

26
00:01:22,000 --> 00:01:25,000
because it's actually the entire posts array

27
00:01:25,000 --> 00:01:29,000
that's being fetched from the database for this posts page.

28
00:01:29,000 --> 00:01:32,000
And it's that entire list of posts that, in the end,

29
00:01:32,000 --> 00:01:34,000
got updated therefore.

30
00:01:35,000 --> 00:01:37,000
So here I'm calling useOptimistic,

31
00:01:37,000 --> 00:01:41,000
but in order to call it we must import this hook from React.

32
00:01:41,000 --> 00:01:44,000
So here at the top of the file you should

33
00:01:44,000 --> 00:01:49,000
import { useOptimistic } from 'react'

34
00:01:50,000 --> 00:01:51,000
Like this.

35
00:01:53,000 --> 00:01:56,000
Now with that, we can call useOptimistic here

36
00:01:56,000 --> 00:01:57,000
in the Posts component.

37
00:01:57,000 --> 00:02:00,000
And this hook now takes a couple of inputs

38
00:02:00,000 --> 00:02:02,000
and gives us a couple of outputs.

39
00:02:02,000 --> 00:02:07,000
The first input it takes is the data

40
00:02:07,000 --> 00:02:08,000
with which we wanna start.

41
00:02:08,000 --> 00:02:11,000
So, the data we fetched from the database.

42
00:02:11,000 --> 00:02:13,000
In this case the post array.

43
00:02:13,000 --> 00:02:17,000
That's the first argument you should pass to useOptimistic.

44
00:02:18,000 --> 00:02:21,000
The second argument is a function

45
00:02:21,000 --> 00:02:24,000
that will be called automatically by React in the end,

46
00:02:24,000 --> 00:02:26,000
when you tell it to call it,

47
00:02:26,000 --> 00:02:29,000
and you'll see how that works in just a second,

48
00:02:29,000 --> 00:02:32,000
that will update this posts array optimistically.

49
00:02:33,000 --> 00:02:35,000
So this will be a function

50
00:02:35,000 --> 00:02:38,000
that changes this post array on the client side

51
00:02:38,000 --> 00:02:42,000
until the change has been processed on the server side,

52
00:02:42,000 --> 00:02:44,000
so that we can change it immediately,

53
00:02:44,000 --> 00:02:47,000
and then only sync it back with that server side state

54
00:02:47,000 --> 00:02:51,000
once that server site update has been performed.

55
00:02:51,000 --> 00:02:55,000
For that, this function should then take two arguments,

56
00:02:55,000 --> 00:03:00,000
where the first argument is the old posts states, so to say.

57
00:03:00,000 --> 00:03:03,000
So, for example, the initial array of posts.

58
00:03:03,000 --> 00:03:06,000
And the second argument is some data

59
00:03:06,000 --> 00:03:09,000
that allows us to perform the update.

60
00:03:09,000 --> 00:03:11,000
And it will be up to us to define

61
00:03:11,000 --> 00:03:13,000
which kind of data we expect here.

62
00:03:13,000 --> 00:03:18,000
In my case here, I expect to get the updatedPostId,

63
00:03:18,000 --> 00:03:20,000
so the ID of the post that should switch

64
00:03:20,000 --> 00:03:24,000
from liked to not liked, or vice versa.

65
00:03:26,000 --> 00:03:30,000
And then we need to add our logic for manipulating the posts

66
00:03:30,000 --> 00:03:33,000
to this function body.

67
00:03:33,000 --> 00:03:35,000
Now before we do that, let's talk about the things

68
00:03:35,000 --> 00:03:37,000
we get back from useOptimistic,

69
00:03:37,000 --> 00:03:40,000
because that will be two elements.

70
00:03:41,000 --> 00:03:45,000
It will be an array with two elements, to be precise.

71
00:03:45,000 --> 00:03:50,000
And the first element will be the updated posts array,

72
00:03:50,000 --> 00:03:52,000
the optimistically updated post array,

73
00:03:52,000 --> 00:03:55,000
and therefore I'll name it optimisticPosts.

74
00:03:58,000 --> 00:04:02,000
The second argument will be a function which we can call

75
00:04:02,000 --> 00:04:05,000
to trigger that optimistic update.

76
00:04:05,000 --> 00:04:08,000
So to trigger this function, which we pass

77
00:04:08,000 --> 00:04:11,000
as a second argument to useOptimistic, in the end.

78
00:04:12,000 --> 00:04:15,000
And I'll call this updateOptimisticPosts.

79
00:04:17,000 --> 00:04:19,000
Obviously these names are up to you.

80
00:04:22,000 --> 00:04:25,000
We can then use the optimistic posts, instead of the posts

81
00:04:25,000 --> 00:04:30,000
from the database, in all the places where we used posts.

82
00:04:30,000 --> 00:04:32,000
So for example here in this if check,

83
00:04:32,000 --> 00:04:35,000
and also here for looping through them.

84
00:04:36,000 --> 00:04:39,000
And we'll soon call this function.

85
00:04:40,000 --> 00:04:43,000
For now, we will just assume that it is being called

86
00:04:43,000 --> 00:04:46,000
with the ID of the post for which the user

87
00:04:46,000 --> 00:04:49,000
changed the like status.

88
00:04:49,000 --> 00:04:51,000
And therefore now in this function body,

89
00:04:51,000 --> 00:04:54,000
we wanna update this posts array accordingly.

90
00:04:54,000 --> 00:04:58,000
And I'll start by getting the index of the post

91
00:04:58,000 --> 00:05:01,000
that should be updated, so that should switch

92
00:05:01,000 --> 00:05:04,000
from liked to not liked, or the other way around.

93
00:05:04,000 --> 00:05:08,000
And we can get that by taking a look at the previous posts.

94
00:05:08,000 --> 00:05:10,000
So the old posts array.

95
00:05:11,000 --> 00:05:13,000
And call the findIndex method,

96
00:05:13,000 --> 00:05:16,000
which is a default method built into JavaScript,

97
00:05:16,000 --> 00:05:20,000
which executes a function on every item in that array.

98
00:05:20,000 --> 00:05:23,000
And in that function we should return true or false.

99
00:05:23,000 --> 00:05:26,000
And for that I'll compare the ID of every post

100
00:05:26,000 --> 00:05:29,000
in that array to the updatedPostId here.

101
00:05:31,000 --> 00:05:34,000
And if we got a match, it will give us the index

102
00:05:34,000 --> 00:05:36,000
of that post in the previous posts array,

103
00:05:36,000 --> 00:05:40,000
and that stands stored in this updatedPostIndex constant.

104
00:05:42,000 --> 00:05:45,000
Now it is possible that we don't find such a post,

105
00:05:45,000 --> 00:05:49,000
and therefore I'll check if updatedPostIndex is equal to -1,

106
00:05:50,000 --> 00:05:53,000
which is a value findIndex will return

107
00:05:53,000 --> 00:05:56,000
if it did not find a post for that condition.

108
00:05:56,000 --> 00:05:58,000
And in that case I just wanna return

109
00:05:58,000 --> 00:06:00,000
the unchanged old posts.

110
00:06:02,000 --> 00:06:05,000
But if we make it past the safe check, we did find a post

111
00:06:05,000 --> 00:06:06,000
that should be updated,

112
00:06:06,000 --> 00:06:09,000
and I wanna update this in a immutable way now.

113
00:06:10,000 --> 00:06:15,000
So I'll create an updatedPost, which is a new object

114
00:06:15,000 --> 00:06:20,000
into which I'll copy all the properties of the old post,

115
00:06:21,000 --> 00:06:24,000
which I'll get by accessing my previous posts

116
00:06:24,000 --> 00:06:26,000
for that updatedPostIndex.

117
00:06:27,000 --> 00:06:30,000
So that will give me access to one specific post.

118
00:06:30,000 --> 00:06:32,000
And I'll spread all the properties

119
00:06:32,000 --> 00:06:34,000
of that post into a new object.

120
00:06:37,000 --> 00:06:40,000
Then I'll change that updatedPost,

121
00:06:40,000 --> 00:06:42,000
and set the likes property, which is the number

122
00:06:42,000 --> 00:06:45,000
of likes this post has, which I'm not using here,

123
00:06:45,000 --> 00:06:48,000
but which I still get from the database.

124
00:06:48,000 --> 00:06:52,000
I'll set that to the updatedPost.likes we had.

125
00:06:52,000 --> 00:06:55,000
And then it depends on whether the post was liked before

126
00:06:55,000 --> 00:06:58,000
or not, because I either want to deduct

127
00:06:58,000 --> 00:07:00,000
the value or add a value.

128
00:07:00,000 --> 00:07:04,000
So I'll check if the updatedPost.isLiked is true.

129
00:07:04,000 --> 00:07:08,000
And if that's the case, I wanna deduct the value,

130
00:07:08,000 --> 00:07:11,000
because it was liked and now it's not liked anymore.

131
00:07:11,000 --> 00:07:14,000
So I want to reduce the number of likes.

132
00:07:14,000 --> 00:07:16,000
Otherwise I want to add a like.

133
00:07:19,000 --> 00:07:22,000
And, more importantly for our application here,

134
00:07:22,000 --> 00:07:26,000
I of course also wanna set the isLiked property

135
00:07:26,000 --> 00:07:30,000
for a given post to the opposite of what it was,

136
00:07:30,000 --> 00:07:35,000
with help of the exclamation mark operator, like this.

137
00:07:36,000 --> 00:07:38,000
This will make sure that we switch it from liked

138
00:07:38,000 --> 00:07:41,000
to not liked, or the other way around.

139
00:07:42,000 --> 00:07:45,000
And then I'll create a newPosts array

140
00:07:45,000 --> 00:07:48,000
where I copy all my old posts.

141
00:07:48,000 --> 00:07:52,000
And I wanna overwrite the post at this updated

142
00:07:52,000 --> 00:07:56,000
postIndexPosition with my updated post.

143
00:07:56,000 --> 00:08:00,000
That would be an immutable way of creating a new posts array

144
00:08:00,000 --> 00:08:03,000
with an updated post based on the old data.

145
00:08:07,000 --> 00:08:09,000
And then here in this function,

146
00:08:09,000 --> 00:08:11,000
which we passed to useOptimistic,

147
00:08:11,000 --> 00:08:15,000
we should return that updated posts array.

148
00:08:17,000 --> 00:08:20,000
And React will then make that updated array available

149
00:08:20,000 --> 00:08:24,000
through that optimisticPosts element it returns

150
00:08:24,000 --> 00:08:27,000
in this array which is returned by useOptimistic.

151
00:08:28,000 --> 00:08:31,000
So all we now have to do is make sure

152
00:08:31,000 --> 00:08:34,000
that we call updateOptimisticPosts,

153
00:08:34,000 --> 00:08:39,000
and that we pass the ID of the post that should be updated

154
00:08:39,000 --> 00:08:40,000
to this function in the end,

155
00:08:40,000 --> 00:08:43,000
so that it will be forwarded to this function.

156
00:08:44,000 --> 00:08:49,000
And we can do that by creating a new action here.

157
00:08:49,000 --> 00:08:52,000
And for that I'll add a action function here.

158
00:08:52,000 --> 00:08:55,000
And I'll name it updatePost.

159
00:08:55,000 --> 00:08:59,000
And I expect to get the postId as an argument here,

160
00:08:59,000 --> 00:09:02,000
just as we did in our server action function before.

161
00:09:02,000 --> 00:09:05,000
And in there I'll call updateOptimisticPosts

162
00:09:06,000 --> 00:09:09,000
and forward the postId to this function.

163
00:09:10,000 --> 00:09:12,000
And that's now, of course, the function

164
00:09:12,000 --> 00:09:15,000
provided by that useOptimistic hook.

165
00:09:15,000 --> 00:09:19,000
And thereafter, I wanna call my togglePostLikeStatus

166
00:09:21,000 --> 00:09:25,000
function, and also pass the postId to that.

167
00:09:28,000 --> 00:09:31,000
And in order to use await here, we should use async here.

168
00:09:31,000 --> 00:09:34,000
And by adding async here, we'll also be able

169
00:09:34,000 --> 00:09:39,000
to use this even though I did not add "use server" here.

170
00:09:39,000 --> 00:09:42,000
But Next.js does allow us to also set functions

171
00:09:42,000 --> 00:09:46,000
like this as client actions, therefore if they have

172
00:09:46,000 --> 00:09:48,000
async in front of them.

173
00:09:48,000 --> 00:09:52,000
So now it's this updatePost function that should be passed

174
00:09:52,000 --> 00:09:54,000
to this post component.

175
00:09:54,000 --> 00:09:57,000
So there we, for example, should add an action prop,

176
00:09:57,000 --> 00:09:59,000
though the name of this prop is up to you

177
00:09:59,000 --> 00:10:01,000
because it's your component.

178
00:10:03,000 --> 00:10:06,000
But you should pass updatePost as a value to that prop.

179
00:10:06,000 --> 00:10:10,000
And then, in that component we should accept

180
00:10:10,000 --> 00:10:13,000
that action prop, or whatever you named it,

181
00:10:13,000 --> 00:10:17,000
and use that as a value for this form action.

182
00:10:17,000 --> 00:10:20,000
And you still should bind the post ID

183
00:10:20,000 --> 00:10:22,000
because we still need that.

184
00:10:23,000 --> 00:10:27,000
But with that, we now again got an extra intermediate

185
00:10:27,000 --> 00:10:30,000
form action that will be executed first,

186
00:10:30,000 --> 00:10:32,000
and that will trigger our optimistic update,

187
00:10:32,000 --> 00:10:34,000
and also make sure that we trigger

188
00:10:34,000 --> 00:10:36,000
that server action behind the scenes.

189
00:10:36,000 --> 00:10:38,000
But thanks to this optimistic update,

190
00:10:38,000 --> 00:10:41,000
the UI should update immediately,

191
00:10:41,000 --> 00:10:44,000
and then the server action still does its thing,

192
00:10:44,000 --> 00:10:47,000
and React and Next.js will then sync everything

193
00:10:47,000 --> 00:10:50,000
thereafter once the server action is done.

194
00:10:50,000 --> 00:10:53,000
That's how you can think about that.

195
00:10:53,000 --> 00:10:56,000
So with that, if you save that all,

196
00:10:56,000 --> 00:10:57,000
you'll see we get an error,

197
00:10:57,000 --> 00:11:01,000
that useOptimistic only works in client components.

198
00:11:02,000 --> 00:11:04,000
Well, that's no problem.

199
00:11:04,000 --> 00:11:07,000
We can simply add "use client" at the top here

200
00:11:07,000 --> 00:11:11,000
because the only server action we're using in that file

201
00:11:11,000 --> 00:11:13,000
is defined in a separate file.

202
00:11:14,000 --> 00:11:17,000
So we can add "use client" without problems here

203
00:11:17,000 --> 00:11:20,000
at the top of this file that holds

204
00:11:20,000 --> 00:11:22,000
the post and posts components.

205
00:11:22,000 --> 00:11:25,000
And with that saved, we can reload again,

206
00:11:25,000 --> 00:11:26,000
we can see our posts.

207
00:11:26,000 --> 00:11:29,000
And now if I unlike that, for example,

208
00:11:29,000 --> 00:11:31,000
you see it's immediately unliked.

209
00:11:31,000 --> 00:11:34,000
If I like it, it's immediately liked here.

210
00:11:34,000 --> 00:11:37,000
And we don't have to wait for that server action to finish.

211
00:11:37,000 --> 00:11:40,000
And that's optimistic updating in action.

