1 00:00:00,000 --> 00:00:03,458 [MUSIC PLAYING] 2 00:00:03,458 --> 00:00:15,808 3 00:00:15,808 --> 00:00:18,460 JORDAN HAYASHI: Hello, and welcome back for Lecture 11. 4 00:00:18,460 --> 00:00:20,439 This week we'll be talking about performance. 5 00:00:20,439 --> 00:00:23,230 So in the previous lecture, we talked about a few different things. 6 00:00:23,230 --> 00:00:26,080 We forged ahead with our simple Redux. 7 00:00:26,080 --> 00:00:30,220 In that one, we did an asynchronous action. 8 00:00:30,220 --> 00:00:34,220 We then saw that it might not be good to change our implementation of reduction 9 00:00:34,220 --> 00:00:35,290 or to do that. 10 00:00:35,290 --> 00:00:37,720 And so we found out what Redux Middleware was, 11 00:00:37,720 --> 00:00:41,650 and by using Redux Middleware, we were able to add asynchronous actions 12 00:00:41,650 --> 00:00:43,180 to Redux itself. 13 00:00:43,180 --> 00:00:45,670 Then we talked about another redux add-on 14 00:00:45,670 --> 00:00:51,400 called Redux Persist, which allows us to store our state into whatever storage 15 00:00:51,400 --> 00:00:55,807 mechanism we want, and then rehydrate our app based on that information. 16 00:00:55,807 --> 00:00:58,390 We then talked about what the difference was between container 17 00:00:58,390 --> 00:00:59,660 and presentational components. 18 00:00:59,660 --> 00:01:02,200 So if you remember, container components are the ones 19 00:01:02,200 --> 00:01:04,209 that are hooked up to your redux state. 20 00:01:04,209 --> 00:01:06,130 And then they pass down props to what are 21 00:01:06,130 --> 00:01:08,020 considered presentational components. 22 00:01:08,020 --> 00:01:12,670 And so presentational components only care about the props 23 00:01:12,670 --> 00:01:15,430 that they need to display themselves. 24 00:01:15,430 --> 00:01:17,920 We then talked about a couple different tools 25 00:01:17,920 --> 00:01:20,500 that we can use for writing JavaScript-- those 26 00:01:20,500 --> 00:01:24,160 being ESLint, which allows us to enforce some style rules, 27 00:01:24,160 --> 00:01:29,260 and Prettier, which allows us to rewrite or automatically rewrite our files such 28 00:01:29,260 --> 00:01:32,520 that they abide by these rules. 29 00:01:32,520 --> 00:01:34,520 So this week we'll be talking about performance. 30 00:01:34,520 --> 00:01:37,060 And so what exactly is performance? 31 00:01:37,060 --> 00:01:41,750 Performance is how quickly or how efficiently something works. 32 00:01:41,750 --> 00:01:43,956 And if we want to make that better, we can do 33 00:01:43,956 --> 00:01:45,580 what's called performance optimization. 34 00:01:45,580 --> 00:01:50,710 And by doing that, we can make something work as efficiently as possible. 35 00:01:50,710 --> 00:01:53,440 Performance optimization is actually a very, very wide field. 36 00:01:53,440 --> 00:01:56,410 But today, we'll only be talking about optimizing 37 00:01:56,410 --> 00:01:58,150 the JavaScript side of things. 38 00:01:58,150 --> 00:02:01,000 I will mostly be talking about high level things 39 00:02:01,000 --> 00:02:04,240 with a few examples along the way. 40 00:02:04,240 --> 00:02:07,240 So one thing that's important about performance 41 00:02:07,240 --> 00:02:09,710 is knowing that there are actually trade-offs involved. 42 00:02:09,710 --> 00:02:13,900 So by optimizing performance, we usually pay some sort of cost. 43 00:02:13,900 --> 00:02:18,590 And this cost is usually in your application's complexity. 44 00:02:18,590 --> 00:02:21,640 So in most cases, it's actually not worth optimizing your code. 45 00:02:21,640 --> 00:02:25,330 JavaScript now is so fast that by optimizing, 46 00:02:25,330 --> 00:02:27,080 you add complexity to your app. 47 00:02:27,080 --> 00:02:29,920 And sometimes that complexity and maintainability 48 00:02:29,920 --> 00:02:35,862 is really not worth the little to no gains that you'll get from optimizing. 49 00:02:35,862 --> 00:02:38,320 And so in general, you don't want to over optimize anything 50 00:02:38,320 --> 00:02:39,730 until you've found a bottleneck. 51 00:02:39,730 --> 00:02:41,730 And by bottleneck, I mean something that's 52 00:02:41,730 --> 00:02:48,290 slow enough that one particular thing slows down your entire app. 53 00:02:48,290 --> 00:02:53,110 And so how do we actually measure for these things called bottlenecks? 54 00:02:53,110 --> 00:02:57,160 Well, there's a few things actually built in. 55 00:02:57,160 --> 00:02:59,440 First, we need to remember what environment 56 00:02:59,440 --> 00:03:00,890 are we running our application in. 57 00:03:00,890 --> 00:03:03,056 And so there are actually two different environments 58 00:03:03,056 --> 00:03:06,610 built into node or our bundler. 59 00:03:06,610 --> 00:03:07,960 One is production. 60 00:03:07,960 --> 00:03:12,610 And one is nonproduction, or what most people consider development mode. 61 00:03:12,610 --> 00:03:16,240 And so the way that we actually set this is in the XTE. 62 00:03:16,240 --> 00:03:18,640 If you click this gear icon here, there's 63 00:03:18,640 --> 00:03:21,232 a dropdown where you can change host, and you can also toggle 64 00:03:21,232 --> 00:03:22,690 this thing called development mode. 65 00:03:22,690 --> 00:03:25,180 And so by checking this and unchecking it, 66 00:03:25,180 --> 00:03:28,600 I can actually determine whether or not my application is running 67 00:03:28,600 --> 00:03:30,790 in development or production mode. 68 00:03:30,790 --> 00:03:33,220 Important to note, if I change this, I should actually 69 00:03:33,220 --> 00:03:37,510 restart the bundler such that it actually is indeed running in the mode 70 00:03:37,510 --> 00:03:40,610 that I want it to be. 71 00:03:40,610 --> 00:03:42,640 React actually has a few optimizations that it 72 00:03:42,640 --> 00:03:44,880 does when it's in production mode. 73 00:03:44,880 --> 00:03:48,460 And so things like prop types aren't necessarily checked. 74 00:03:48,460 --> 00:03:52,672 And warnings and errors are not necessarily displayed. 75 00:03:52,672 --> 00:03:55,570 76 00:03:55,570 --> 00:03:58,030 So there's a few tools built into React Native itself 77 00:03:58,030 --> 00:04:01,780 that allow us to benchmark our performance. 78 00:04:01,780 --> 00:04:04,240 And so one is called the React Native Perf Monitor-- 79 00:04:04,240 --> 00:04:06,310 Performance Monitor. 80 00:04:06,310 --> 00:04:08,950 What this does is it shows you the refresh rate of both 81 00:04:08,950 --> 00:04:10,610 your UI and your JavaScript threads. 82 00:04:10,610 --> 00:04:15,130 So if you remember back to our lecture on React Native, 83 00:04:15,130 --> 00:04:17,920 we talked about how there was one thread for rendering 84 00:04:17,920 --> 00:04:20,140 the UI on the native side, and one thread that's 85 00:04:20,140 --> 00:04:22,060 actually executing your JavaScript. 86 00:04:22,060 --> 00:04:25,090 And so this React Native Perf Monitor allows 87 00:04:25,090 --> 00:04:28,050 us to see the refresh rate on both these threads. 88 00:04:28,050 --> 00:04:29,850 And so anything below 60 frames per second 89 00:04:29,850 --> 00:04:31,600 means we're actually dropping some frames. 90 00:04:31,600 --> 00:04:35,540 And so there is potentially a bottleneck in whatever we're dealing with. 91 00:04:35,540 --> 00:04:39,370 And so to show you how that works, I'm running this simple application here. 92 00:04:39,370 --> 00:04:42,360 What we can do is shake the device, and it brings up this menu. 93 00:04:42,360 --> 00:04:45,000 And we can click the Show Perf Monitor. 94 00:04:45,000 --> 00:04:47,590 And that shows this thing here, which is draggable, 95 00:04:47,590 --> 00:04:50,690 which shows us a few things-- 96 00:04:50,690 --> 00:04:53,170 one is how much RAM we're actually using, 97 00:04:53,170 --> 00:04:56,980 so how much memory is your application consuming. 98 00:04:56,980 --> 00:05:00,520 And of that memory, how much is being consumed by the JavaScript 99 00:05:00,520 --> 00:05:02,860 itself or the JavaScript core. 100 00:05:02,860 --> 00:05:06,100 We then see how many views are in our application. 101 00:05:06,100 --> 00:05:09,550 The top number refers to how many are currently in view. 102 00:05:09,550 --> 00:05:12,232 And the bottom number is how many there are just total. 103 00:05:12,232 --> 00:05:15,190 And then we see the two things that I mentioned-- the UI and JavaScript 104 00:05:15,190 --> 00:05:16,300 frames per second meters. 105 00:05:16,300 --> 00:05:19,020 And so since they're both locked at 60 frames per second, 106 00:05:19,020 --> 00:05:21,940 it means we're not dropping any frames, or there's no bottleneck 107 00:05:21,940 --> 00:05:24,950 in what we're currently doing here. 108 00:05:24,950 --> 00:05:30,080 And so what happens if we actually want to introduce a bottleneck? 109 00:05:30,080 --> 00:05:31,880 And so if you remember back a few lectures, 110 00:05:31,880 --> 00:05:38,530 we implemented this application where we just display a bunch of contacts. 111 00:05:38,530 --> 00:05:41,620 And these contacts are generated by that contacts.js file 112 00:05:41,620 --> 00:05:43,910 that we talked about a few weeks ago. 113 00:05:43,910 --> 00:05:47,080 And in this case, I actually reverted back to our scroll view. 114 00:05:47,080 --> 00:05:51,910 If you remember, scroll view versus flat list or section list, the flat list 115 00:05:51,910 --> 00:05:55,510 and section lists are virtualized lists, which means they only 116 00:05:55,510 --> 00:05:57,617 render what's currently in view. 117 00:05:57,617 --> 00:06:00,700 Whereas the scroll view will actually render everything before displaying. 118 00:06:00,700 --> 00:06:03,970 And so if we toggle it and then turn it back on, 119 00:06:03,970 --> 00:06:06,610 we see that our JavaScript thread does indeed 120 00:06:06,610 --> 00:06:08,570 drop well below 60 frames per second. 121 00:06:08,570 --> 00:06:11,560 So once again, we can toggle this. 122 00:06:11,560 --> 00:06:15,610 And then when we toggle it again, it has to render all of these contacts. 123 00:06:15,610 --> 00:06:17,260 I believe there are 1,000 being shown. 124 00:06:17,260 --> 00:06:20,440 And we see a dip in the frames per second in our JavaScript thread. 125 00:06:20,440 --> 00:06:23,320 126 00:06:23,320 --> 00:06:23,820 Cool. 127 00:06:23,820 --> 00:06:27,660 And so by using this Perf Monitor, we can navigate through our app 128 00:06:27,660 --> 00:06:33,920 and find out exactly what screens are causing any frames dropped. 129 00:06:33,920 --> 00:06:38,190 If we want more detail, we can use what is called the Chrome Performance 130 00:06:38,190 --> 00:06:39,120 Profiler-- 131 00:06:39,120 --> 00:06:42,330 and so I alluded to this a little bit last week-- 132 00:06:42,330 --> 00:06:47,550 where we can actually run our JavaScript inside of Google Chrome. 133 00:06:47,550 --> 00:06:51,950 And so we've done this a few times in the past. 134 00:06:51,950 --> 00:07:00,710 And what this does is it shows you a flame chart of all of your components. 135 00:07:00,710 --> 00:07:03,830 And I'll show you what that means in just a second. 136 00:07:03,830 --> 00:07:07,280 But one thing to note is that this is only available in development mode. 137 00:07:07,280 --> 00:07:10,610 If you're running your application in production mode, 138 00:07:10,610 --> 00:07:12,930 this option will not be available for you. 139 00:07:12,930 --> 00:07:15,470 And so since we are indeed in development mode, 140 00:07:15,470 --> 00:07:17,930 we can use this debugger. 141 00:07:17,930 --> 00:07:22,790 And so what I did was shake my device, bring up this remote debugger, 142 00:07:22,790 --> 00:07:28,220 I clicked on it, and it's now running my JavaScript inside of Google Chrome. 143 00:07:28,220 --> 00:07:31,820 And so we talked about how the JavaScript is actually 144 00:07:31,820 --> 00:07:33,225 separate from the UI threads. 145 00:07:33,225 --> 00:07:35,600 And the way that they communicate is through this bridge. 146 00:07:35,600 --> 00:07:37,766 And so it doesn't really matter where our JavaScript 147 00:07:37,766 --> 00:07:40,530 is running, as long as it can communicate with our UI thread. 148 00:07:40,530 --> 00:07:43,550 And so since it's running currently in Google Chrome, 149 00:07:43,550 --> 00:07:46,310 I can inspect and see what's going on. 150 00:07:46,310 --> 00:07:49,050 And so here you can see elements-- 151 00:07:49,050 --> 00:07:50,840 Console, Sources, Network. 152 00:07:50,840 --> 00:07:53,720 But the tab we're actually looking for right now is Performance. 153 00:07:53,720 --> 00:07:56,720 And so here we see a bunch of options. 154 00:07:56,720 --> 00:08:00,740 We can click the record button or press Command E to start a new recording. 155 00:08:00,740 --> 00:08:04,670 We can click the reload button, which will reload the frame 156 00:08:04,670 --> 00:08:05,712 and record the page load. 157 00:08:05,712 --> 00:08:08,045 Unfortunately, this doesn't really work in React Native. 158 00:08:08,045 --> 00:08:10,350 It's more something that's geared towards web. 159 00:08:10,350 --> 00:08:13,130 But what we can do is we can press the record button, 160 00:08:13,130 --> 00:08:15,710 do a few things in our application, and then come back 161 00:08:15,710 --> 00:08:19,135 and see exactly what has happened in our JavaScript. 162 00:08:19,135 --> 00:08:22,320 And so let's toggle these so that they're not visible. 163 00:08:22,320 --> 00:08:26,320 Let's start a new profile recording. 164 00:08:26,320 --> 00:08:27,470 Go back. 165 00:08:27,470 --> 00:08:29,179 Toggle them. 166 00:08:29,179 --> 00:08:29,720 You see that. 167 00:08:29,720 --> 00:08:30,900 It took a while to render. 168 00:08:30,900 --> 00:08:33,530 And then we can go ahead and stop this profile. 169 00:08:33,530 --> 00:08:36,299 And then Chrome will analyze things and show us this chart here. 170 00:08:36,299 --> 00:08:40,909 And so we see Frames, Interactions, Main, Raster, GPU, User Timing. 171 00:08:40,909 --> 00:08:44,179 And what we're looking for here is User Timing. 172 00:08:44,179 --> 00:08:49,520 If we dive into User Timing, we can see a few things. 173 00:08:49,520 --> 00:08:51,470 We see the React Tree Reconciliation. 174 00:08:51,470 --> 00:08:56,720 We see a Contact Screen Update, which is our contact screen that we have here. 175 00:08:56,720 --> 00:09:00,470 We have a Scroll View Contacts, Scroll View mount, 176 00:09:00,470 --> 00:09:02,430 and then we see a bunch of things. 177 00:09:02,430 --> 00:09:05,180 And if we zoom in all the way, we can actually 178 00:09:05,180 --> 00:09:09,770 see that each one here is a row being mounted. 179 00:09:09,770 --> 00:09:13,250 And so this is what a flame chart looks like. 180 00:09:13,250 --> 00:09:18,790 A flame chart is a chart that is basically our React Tree 181 00:09:18,790 --> 00:09:20,370 but graphed out over time. 182 00:09:20,370 --> 00:09:24,710 And so we can see these numbers up here which correspond to the time line since 183 00:09:24,710 --> 00:09:29,330 we clicked that record button and what is happening as these milliseconds tick 184 00:09:29,330 --> 00:09:31,820 by-- so you see 3,600 milliseconds-- 185 00:09:31,820 --> 00:09:33,440 3,650 milliseconds. 186 00:09:33,440 --> 00:09:36,640 And so in this 50 millisecond time span, what has happened? 187 00:09:36,640 --> 00:09:41,660 Well, we have been rendering our Scroll View Contacts. 188 00:09:41,660 --> 00:09:44,150 We've been rendering our Scroll View. 189 00:09:44,150 --> 00:09:49,607 And within that 50 millisecond thing, we see that all of this happened. 190 00:09:49,607 --> 00:09:50,690 And what exactly is there? 191 00:09:50,690 --> 00:09:59,150 Well, we can zoom in and see that we've rendered a few rows. 192 00:09:59,150 --> 00:10:02,810 And what happens at each row mount? 193 00:10:02,810 --> 00:10:04,640 Well, there's a View in there. 194 00:10:04,640 --> 00:10:05,450 There's some Text. 195 00:10:05,450 --> 00:10:06,560 There's another Text. 196 00:10:06,560 --> 00:10:08,630 And there's a Text Context. 197 00:10:08,630 --> 00:10:13,490 So we can see that for every single component that we have in our tree, 198 00:10:13,490 --> 00:10:16,100 each one takes a little bit of time to render. 199 00:10:16,100 --> 00:10:19,430 And we can see exactly what's being rendered 200 00:10:19,430 --> 00:10:21,320 by looking at this flame chart. 201 00:10:21,320 --> 00:10:28,490 And so if we refer back to our code, we can see that the app, all it's doing-- 202 00:10:28,490 --> 00:10:31,310 I removed a lot of the stuff that we did last week since it's not 203 00:10:31,310 --> 00:10:35,240 necessary for this particular example-- 204 00:10:35,240 --> 00:10:37,550 I have my ESLint thing popped up. 205 00:10:37,550 --> 00:10:44,210 206 00:10:44,210 --> 00:10:46,910 We can see that this app is only doing one thing. 207 00:10:46,910 --> 00:10:51,200 It's rendering provider, which, as we remember from last week, 208 00:10:51,200 --> 00:10:56,570 is what allows us to access our Redux store anywhere in our app that's 209 00:10:56,570 --> 00:10:58,730 given to us by React Redux. 210 00:10:58,730 --> 00:11:03,397 We see a view which just has a few different styles. 211 00:11:03,397 --> 00:11:04,980 Then we have our contacts list screen. 212 00:11:04,980 --> 00:11:06,480 And so what is being rendered there? 213 00:11:06,480 --> 00:11:14,700 214 00:11:14,700 --> 00:11:22,120 The Contacts List screen is just rendering our contacts a list. 215 00:11:22,120 --> 00:11:24,450 And what exactly is our Contacts List? 216 00:11:24,450 --> 00:11:29,180 Well, it's defined here to be the Scroll View Contacts. 217 00:11:29,180 --> 00:11:30,555 And what is Scroll View Contacts? 218 00:11:30,555 --> 00:11:36,670 219 00:11:36,670 --> 00:11:40,480 We can see that it suggests-- 220 00:11:40,480 --> 00:11:42,530 let me silence these errors real quick. 221 00:11:42,530 --> 00:12:00,875 222 00:12:00,875 --> 00:12:03,750 So I'm running [INAUDIBLE] really quick just to silence those errors. 223 00:12:03,750 --> 00:12:12,680 And then now I can view without my ESLint integration popping up. 224 00:12:12,680 --> 00:12:14,940 And so Scroll View Contacts is just a Scroll View. 225 00:12:14,940 --> 00:12:18,510 And what it's doing is it's taking our contacts, which is an array that's 226 00:12:18,510 --> 00:12:20,460 passed down, it's mapping over them. 227 00:12:20,460 --> 00:12:23,680 And for each contact, we're rendering a row. 228 00:12:23,680 --> 00:12:26,617 And so we can actually see this exact structure of our app 229 00:12:26,617 --> 00:12:27,450 in that flame chart. 230 00:12:27,450 --> 00:12:29,310 And so we saw our app. 231 00:12:29,310 --> 00:12:33,011 We saw that it's rendering something called the Contacts List screen. 232 00:12:33,011 --> 00:12:35,010 We saw that the Contacts List screen is actually 233 00:12:35,010 --> 00:12:36,960 rendering the Scroll View Contacts. 234 00:12:36,960 --> 00:12:39,020 And we see that the Scroll View Contacts is 235 00:12:39,020 --> 00:12:43,160 a Scroll View with a number of rows that corresponds to the number of contacts. 236 00:12:43,160 --> 00:12:46,560 And if we again refer to that flame chart, 237 00:12:46,560 --> 00:12:54,090 we see our app, which is the top level component. 238 00:12:54,090 --> 00:12:55,947 We see our Contacts List screen. 239 00:12:55,947 --> 00:12:57,780 We then see that it has a view inside of it. 240 00:12:57,780 --> 00:12:59,670 And inside that view, we have our component 241 00:12:59,670 --> 00:13:01,830 called the Scroll View Contacts. 242 00:13:01,830 --> 00:13:04,960 We see that that is actually rendering a Scroll View. 243 00:13:04,960 --> 00:13:07,010 And so if we just double check the code, we 244 00:13:07,010 --> 00:13:09,630 can see that we have indeed a component called 245 00:13:09,630 --> 00:13:12,300 Scroll View Contacts, which is indeed rendering 246 00:13:12,300 --> 00:13:14,520 something that is a Scroll View. 247 00:13:14,520 --> 00:13:19,270 And then inside of that Scroll View, we see a large number of rows. 248 00:13:19,270 --> 00:13:25,440 And each row is referring to a row that is rendered right here. 249 00:13:25,440 --> 00:13:28,230 And so this is just timing for us all of the components 250 00:13:28,230 --> 00:13:30,180 that we have in our tree. 251 00:13:30,180 --> 00:13:37,150 And so it might be inefficient to render all 1,000 rows 252 00:13:37,150 --> 00:13:39,340 when we want to just mount that app. 253 00:13:39,340 --> 00:13:41,290 And so what we want to do instead-- 254 00:13:41,290 --> 00:13:44,250 well, we saw a few weeks ago that we can actually, 255 00:13:44,250 --> 00:13:47,970 rather than using a Scroll View, we can use a Virtualized List, a list that 256 00:13:47,970 --> 00:13:50,790 only renders what's in view currently. 257 00:13:50,790 --> 00:13:53,640 So let's go ahead and do that. 258 00:13:53,640 --> 00:13:59,847 We have implemented from a few weeks ago that Section List Contacts. 259 00:13:59,847 --> 00:14:01,930 And in here, we are actually using a Section List, 260 00:14:01,930 --> 00:14:06,140 which is indeed a Virtualized List. 261 00:14:06,140 --> 00:14:09,460 So again, let me silence these errors. 262 00:14:09,460 --> 00:14:27,270 263 00:14:27,270 --> 00:14:40,780 So here, disable this next line, and here as well. 264 00:14:40,780 --> 00:15:06,330 265 00:15:06,330 --> 00:15:09,890 All right, so this should shut up those errors. 266 00:15:09,890 --> 00:15:12,590 And so we see here that we have our Section List, which 267 00:15:12,590 --> 00:15:17,420 does a little bit of logic in order to separate our array of contacts 268 00:15:17,420 --> 00:15:21,500 into the data structure that the Section List is looking for. 269 00:15:21,500 --> 00:15:24,980 And then it goes ahead and renders a Section List. 270 00:15:24,980 --> 00:15:27,620 And so this is code that we wrote a few lectures ago. 271 00:15:27,620 --> 00:15:31,070 And we see that we pass it a render item, which 272 00:15:31,070 --> 00:15:33,600 it will use to render the items as they appear on screen. 273 00:15:33,600 --> 00:15:37,370 And so it's important to note that only what's currently in view 274 00:15:37,370 --> 00:15:38,120 is being rendered. 275 00:15:38,120 --> 00:15:40,610 It's not rendering all 1,000 of these contacts 276 00:15:40,610 --> 00:15:43,330 before it's showing it on the screen. 277 00:15:43,330 --> 00:15:51,840 And so let's go ahead and in our Contacts List screen, 278 00:15:51,840 --> 00:15:55,920 we can go ahead and flip this Boolean here 279 00:15:55,920 --> 00:16:01,800 so that it's rendering the Flat List Contacts rather than the Scroll View 280 00:16:01,800 --> 00:16:02,490 Contacts. 281 00:16:02,490 --> 00:16:06,370 I just did this so it's easy to do this quickly during lecture, 282 00:16:06,370 --> 00:16:07,370 so I don't have to type. 283 00:16:07,370 --> 00:16:10,600 284 00:16:10,600 --> 00:16:15,260 So we can now see that this now renders almost instantaneously. 285 00:16:15,260 --> 00:16:18,570 It's just because it's only rendering what's in view. 286 00:16:18,570 --> 00:16:22,570 And so let's now do this again. 287 00:16:22,570 --> 00:16:24,220 Make sure it's not in View. 288 00:16:24,220 --> 00:16:26,830 Start recording a profile. 289 00:16:26,830 --> 00:16:28,210 Render the View. 290 00:16:28,210 --> 00:16:29,511 And then stop. 291 00:16:29,511 --> 00:16:31,510 And now we can go ahead and see this flame chart 292 00:16:31,510 --> 00:16:38,960 to see if it's rendering as many contacts as the Scroll View did. 293 00:16:38,960 --> 00:16:41,060 And now we see something very different. 294 00:16:41,060 --> 00:16:43,820 295 00:16:43,820 --> 00:16:46,660 We see over here our app. 296 00:16:46,660 --> 00:16:48,740 It's added a Virtualized List. 297 00:16:48,740 --> 00:16:51,955 It turns out the Virtualized List within it has a Scroll View. 298 00:16:51,955 --> 00:16:54,130 And let's see how many rows are being rendered. 299 00:16:54,130 --> 00:16:57,070 300 00:16:57,070 --> 00:16:59,410 Now we get to peek into the internals of how 301 00:16:59,410 --> 00:17:02,410 this Section List is being rendered. 302 00:17:02,410 --> 00:17:06,430 So we see that there's a View with a cell render. 303 00:17:06,430 --> 00:17:08,500 Inside that cell render is the row being called. 304 00:17:08,500 --> 00:17:10,300 And inside that is a View. 305 00:17:10,300 --> 00:17:14,020 So inside the row is exactly what we have inside our row implementation. 306 00:17:14,020 --> 00:17:16,660 It's a view with a couple pieces of text in it. 307 00:17:16,660 --> 00:17:19,660 Those text are just the name and the phone number. 308 00:17:19,660 --> 00:17:24,040 But we see that one, two, three, four, five, six-- 309 00:17:24,040 --> 00:17:26,710 a lot fewer than 1,000 of these are being rendered. 310 00:17:26,710 --> 00:17:29,910 And the reason is because it's only rendering what's in View. 311 00:17:29,910 --> 00:17:34,770 And so we can actually see proof of that by one, just toggling the button 312 00:17:34,770 --> 00:17:38,052 and seeing that it renders almost instantaneously, but two, 313 00:17:38,052 --> 00:17:39,760 actually just looking at this flame chart 314 00:17:39,760 --> 00:17:42,640 and seeing that within this Scroll View here, 315 00:17:42,640 --> 00:17:48,430 there's actually only like 15, maybe 20 rows that are being rendered, 316 00:17:48,430 --> 00:17:50,620 rather than all 1,000 like the previous one. 317 00:17:50,620 --> 00:17:54,920 And if we wanted to take a peek at the internals and see how this works, 318 00:17:54,920 --> 00:17:59,170 we can see that there's a Virtualized List or our Section List 319 00:17:59,170 --> 00:18:02,290 that we're using is actually calling a Virtualized List under the hood. 320 00:18:02,290 --> 00:18:05,440 And that Virtualized List is actually using a Scroll View under the hood. 321 00:18:05,440 --> 00:18:10,500 And so we get a peek at the internals of this component. 322 00:18:10,500 --> 00:18:14,334 All right, so let's now stop remote debugging, so we can forge ahead. 323 00:18:14,334 --> 00:18:21,250 324 00:18:21,250 --> 00:18:24,880 So now that we've seen how to actually look at the performance of our app, 325 00:18:24,880 --> 00:18:27,430 let's start to actually optimize some things. 326 00:18:27,430 --> 00:18:32,630 So what are some common inefficiencies in React Native apps? 327 00:18:32,630 --> 00:18:35,230 So one is just re-rendering way too often. 328 00:18:35,230 --> 00:18:38,620 Another one is unnecessarily changing props, 329 00:18:38,620 --> 00:18:41,620 and lastly, unnecessary logic in mount update. 330 00:18:41,620 --> 00:18:44,900 And so what does it mean to re-render too often? 331 00:18:44,900 --> 00:18:47,727 Well, components actually automatically re-render 332 00:18:47,727 --> 00:18:49,060 whenever they receive new props. 333 00:18:49,060 --> 00:18:52,340 We've been talking about this since nearly day one. 334 00:18:52,340 --> 00:18:57,910 But sometimes a prop that isn't necessarily needed is passed. 335 00:18:57,910 --> 00:19:01,577 And then if that changed, it also requires the entire component 336 00:19:01,577 --> 00:19:02,260 to re-render. 337 00:19:02,260 --> 00:19:05,710 And sometimes that's completely unnecessary. 338 00:19:05,710 --> 00:19:08,880 And so how do we actually go about fixing that? 339 00:19:08,880 --> 00:19:10,630 Well, if we're using something like Redux, 340 00:19:10,630 --> 00:19:14,450 we only need to subscribe to the part of the state that we actually care about. 341 00:19:14,450 --> 00:19:17,170 And so in our maps [INAUDIBLE] to props function, 342 00:19:17,170 --> 00:19:22,450 no need to subscribe to some props that aren't necessary for the app. 343 00:19:22,450 --> 00:19:25,340 So that one's a pretty easy optimization. 344 00:19:25,340 --> 00:19:28,030 Another thing is using keys in arrays or lists. 345 00:19:28,030 --> 00:19:32,540 And so in a few lectures ago, we talked about why that's necessary. 346 00:19:32,540 --> 00:19:34,930 And so if you remember back to then, the way 347 00:19:34,930 --> 00:19:40,310 that React works is that every single time a component is re-rendered, 348 00:19:40,310 --> 00:19:46,570 it will actually diff something in the virtual React Tree 349 00:19:46,570 --> 00:19:49,660 with what's actually rendered to the app. 350 00:19:49,660 --> 00:19:55,280 And so if we have something like a list of maybe names. 351 00:19:55,280 --> 00:19:58,340 And maybe the first one is Jordan. 352 00:19:58,340 --> 00:20:01,810 And the second one's David. 353 00:20:01,810 --> 00:20:03,970 And say we wanted to add a new person. 354 00:20:03,970 --> 00:20:10,470 If we wanted to add somebody like Yowon and we 355 00:20:10,470 --> 00:20:13,800 wanted to add it to the third place in the list, it's pretty easy for React 356 00:20:13,800 --> 00:20:14,760 to do. 357 00:20:14,760 --> 00:20:21,420 It says, OK, we need to add something to our virtual list 358 00:20:21,420 --> 00:20:23,397 and say this is what's currently on screen, 359 00:20:23,397 --> 00:20:24,980 or this is what's currently on screen. 360 00:20:24,980 --> 00:20:29,520 361 00:20:29,520 --> 00:20:32,210 And this is what it's doing in memory. 362 00:20:32,210 --> 00:20:36,140 So it can say, OK, we're going to add Yowon to the list here. 363 00:20:36,140 --> 00:20:37,980 And so let's do this in red. 364 00:20:37,980 --> 00:20:42,370 365 00:20:42,370 --> 00:20:45,670 And then it can go ahead and do a diff, which was actually there. 366 00:20:45,670 --> 00:20:47,295 It says, oh, this remains the same. 367 00:20:47,295 --> 00:20:48,420 We don't need to change it. 368 00:20:48,420 --> 00:20:49,380 This remains the same. 369 00:20:49,380 --> 00:20:50,380 Don't need to change it. 370 00:20:50,380 --> 00:20:54,400 Oh, Yowon doesn't exist in the actual tree, so let's add him here. 371 00:20:54,400 --> 00:20:58,641 372 00:20:58,641 --> 00:20:59,140 Easy. 373 00:20:59,140 --> 00:21:02,560 All we had to do is add one person at the bottom. 374 00:21:02,560 --> 00:21:06,024 But what happens when we don't want to add the person to the bottom? 375 00:21:06,024 --> 00:21:07,690 So let's retrace our steps a little bit. 376 00:21:07,690 --> 00:21:14,840 377 00:21:14,840 --> 00:21:21,710 Say the goal was actually to add Yowon to the top of the list. 378 00:21:21,710 --> 00:21:23,370 Then what needs to happen? 379 00:21:23,370 --> 00:21:27,170 Well, if React was just to do its thing and diff, 380 00:21:27,170 --> 00:21:29,410 it would say, OK, let's add Yowon here. 381 00:21:29,410 --> 00:21:32,730 382 00:21:32,730 --> 00:21:34,560 And now we have this new list. 383 00:21:34,560 --> 00:21:37,130 So what's different between the first people on the list? 384 00:21:37,130 --> 00:21:39,046 Well, they're different, so let's change this. 385 00:21:39,046 --> 00:21:41,840 386 00:21:41,840 --> 00:21:43,694 How about the second person in the list? 387 00:21:43,694 --> 00:21:46,360 Well, Jordan is different than David, so we need to change that. 388 00:21:46,360 --> 00:21:49,930 389 00:21:49,930 --> 00:21:51,890 And then who's third? 390 00:21:51,890 --> 00:21:54,250 Well, nobody's there, so let's just-- 391 00:21:54,250 --> 00:21:56,300 oops. 392 00:21:56,300 --> 00:21:59,884 This should be Jordan. 393 00:21:59,884 --> 00:22:02,730 394 00:22:02,730 --> 00:22:08,820 And then nobody's in the third list here, so let's just add David. 395 00:22:08,820 --> 00:22:10,730 So what ends up happening in this case is 396 00:22:10,730 --> 00:22:15,560 we changed all three things when you really only needed to change one. 397 00:22:15,560 --> 00:22:17,990 And so by adding keys to a list, React can actually 398 00:22:17,990 --> 00:22:24,650 keep track of what was in the new list that was originally in the list, 399 00:22:24,650 --> 00:22:26,630 even if the order has changed. 400 00:22:26,630 --> 00:22:29,630 And so let's just redraw this. 401 00:22:29,630 --> 00:22:38,010 402 00:22:38,010 --> 00:22:44,340 [INAUDIBLE] all this we had Jordan and David here. 403 00:22:44,340 --> 00:22:46,628 And then we wanted to add Yowon to the beginning. 404 00:22:46,628 --> 00:22:49,320 405 00:22:49,320 --> 00:22:53,070 What happens in this case if we were to mark them and say maybe 406 00:22:53,070 --> 00:22:55,710 Jordan's ID is just the number 1. 407 00:22:55,710 --> 00:22:58,380 And maybe David's ID is the number 2. 408 00:22:58,380 --> 00:23:00,450 And maybe Yowon's ID is the number 3. 409 00:23:00,450 --> 00:23:12,860 410 00:23:12,860 --> 00:23:15,830 And so now we've marked them with what are effectively IDs. 411 00:23:15,830 --> 00:23:17,360 So what happens now? 412 00:23:17,360 --> 00:23:20,600 React says, oh, we need to add Yowon to the beginning of the list. 413 00:23:20,600 --> 00:23:28,200 414 00:23:28,200 --> 00:23:32,280 And now let us diff what is in the new list in the memory with what 415 00:23:32,280 --> 00:23:34,200 we actually have here. 416 00:23:34,200 --> 00:23:36,487 Oh, Yowon 3 doesn't match Jordan. 417 00:23:36,487 --> 00:23:38,070 But this here actually has a number 1. 418 00:23:38,070 --> 00:23:39,611 And we see that the number 1 is here. 419 00:23:39,611 --> 00:23:42,626 Oh, we also see that David is still here, so we don't actually 420 00:23:42,626 --> 00:23:43,500 have to change these. 421 00:23:43,500 --> 00:23:47,412 We know that what used to be part of the-- 422 00:23:47,412 --> 00:23:50,400 the items that used to be in the list are still on the new list. 423 00:23:50,400 --> 00:23:52,290 They just changed their orders. 424 00:23:52,290 --> 00:23:55,110 So we can actually just move those components down the list 425 00:23:55,110 --> 00:23:59,820 and add one new person here. 426 00:23:59,820 --> 00:24:04,630 So React is smart enough to know, hey, these particular people didn't change. 427 00:24:04,630 --> 00:24:07,270 They just shifted places in the list. 428 00:24:07,270 --> 00:24:11,950 And so in the new list, now that we don't have to recreate them, 429 00:24:11,950 --> 00:24:14,760 we can just shuffle them around, reuse them, 430 00:24:14,760 --> 00:24:17,400 and add only what's needed to be added. 431 00:24:17,400 --> 00:24:21,210 And the only way that we can allow React to have the optimization 432 00:24:21,210 --> 00:24:23,280 is by marking people with these IDs. 433 00:24:23,280 --> 00:24:25,830 And these IDs must actually be unique. 434 00:24:25,830 --> 00:24:27,420 Otherwise, it won't know-- 435 00:24:27,420 --> 00:24:32,040 say we had some third person here in the list with an ID of number 1. 436 00:24:32,040 --> 00:24:36,260 When it sees Jordan 1 here, it won't know which one it should be. 437 00:24:36,260 --> 00:24:38,940 And so it'll actually throw a warning, oh, Key Error. 438 00:24:38,940 --> 00:24:41,250 We have multiple of the same keys. 439 00:24:41,250 --> 00:24:44,730 And so the constraint on this is that we must have unique keys. 440 00:24:44,730 --> 00:24:48,710 But by assigning keys to each member in a list, 441 00:24:48,710 --> 00:24:50,565 React can have this optimization. 442 00:24:50,565 --> 00:24:57,000 443 00:24:57,000 --> 00:25:01,409 And lastly, we have shouldComponentUpdate, 444 00:25:01,409 --> 00:25:03,200 which we talked about in the previous weeks 445 00:25:03,200 --> 00:25:05,639 when we talked about React lifecycle methods. 446 00:25:05,639 --> 00:25:07,430 shouldComponentUpdate is a lifecycle method 447 00:25:07,430 --> 00:25:10,941 that allows us to either return true or return false. 448 00:25:10,941 --> 00:25:12,940 If we return true, we're answering the question, 449 00:25:12,940 --> 00:25:14,680 should the component update with yes. 450 00:25:14,680 --> 00:25:16,850 And it will go ahead and re-render. 451 00:25:16,850 --> 00:25:20,046 If we return false, then we're answering the question, 452 00:25:20,046 --> 00:25:21,545 should the component update with no. 453 00:25:21,545 --> 00:25:24,270 And it will actually not re-render. 454 00:25:24,270 --> 00:25:27,020 And then we see this new thing called a React PureComponent, which 455 00:25:27,020 --> 00:25:29,160 we have never talked about so far. 456 00:25:29,160 --> 00:25:31,230 So we've talked about a React.Component. 457 00:25:31,230 --> 00:25:33,080 Many times, what is a React.Component? 458 00:25:33,080 --> 00:25:35,969 Well, it's just the basic building block of React. 459 00:25:35,969 --> 00:25:37,010 And what does it give us? 460 00:25:37,010 --> 00:25:38,260 It gives us things like state. 461 00:25:38,260 --> 00:25:40,400 It gives us those lifecycle methods. 462 00:25:40,400 --> 00:25:43,250 But it turns out there's another thing called a React PureComponent. 463 00:25:43,250 --> 00:25:46,490 And what differs here is that a PureComponent 464 00:25:46,490 --> 00:25:49,730 has a predefined shouldComponentUpdate where it just 465 00:25:49,730 --> 00:25:52,760 does a shallow diff of props, meaning it looks at the props 466 00:25:52,760 --> 00:25:53,879 that it used to have. 467 00:25:53,879 --> 00:25:56,420 It looks at the props and the new props that are coming down. 468 00:25:56,420 --> 00:25:58,550 And it will compare each one. 469 00:25:58,550 --> 00:26:00,380 And it does this at a level. 470 00:26:00,380 --> 00:26:04,970 And I think we talked about a shallow merge back in Lecture 1. 471 00:26:04,970 --> 00:26:07,400 But it just means it will look at each prop. 472 00:26:07,400 --> 00:26:11,734 It will say, does this prop triple equal this new prop? 473 00:26:11,734 --> 00:26:14,150 And so if it's something like an object, it won't actually 474 00:26:14,150 --> 00:26:16,170 dive into the keys of the objects. 475 00:26:16,170 --> 00:26:19,100 It'll just see if the object references match. 476 00:26:19,100 --> 00:26:21,770 And same with something like a function, or a array, 477 00:26:21,770 --> 00:26:27,020 or any other object type in JavaScript. 478 00:26:27,020 --> 00:26:31,320 So let's go ahead and do something here. 479 00:26:31,320 --> 00:26:33,500 So let's add something to our app that will actually 480 00:26:33,500 --> 00:26:38,030 change the first contact in our list. 481 00:26:38,030 --> 00:26:44,210 So let's revert back to our Scroll View just so 482 00:26:44,210 --> 00:26:47,270 that any performance hits are noticeable because it 483 00:26:47,270 --> 00:26:56,080 is re-rendering 1,000 rows at once. 484 00:26:56,080 --> 00:26:58,990 So now you can see that it takes a good second in order 485 00:26:58,990 --> 00:27:01,080 to render this full screen. 486 00:27:01,080 --> 00:27:03,970 And so let's add something-- like some sort of button 487 00:27:03,970 --> 00:27:06,710 maybe here where when you click this button, 488 00:27:06,710 --> 00:27:09,580 it just changes the first person in the app. 489 00:27:09,580 --> 00:27:14,260 And presumably, we won't need to re-render all 999 other people. 490 00:27:14,260 --> 00:27:19,870 But we'll see how we can tell React explicitly, hey, don't re-render these. 491 00:27:19,870 --> 00:27:22,984 And we're going to use something like shouldComponentUpdate. 492 00:27:22,984 --> 00:27:26,620 493 00:27:26,620 --> 00:27:29,720 So let's just do a quick review of what's actually happening here. 494 00:27:29,720 --> 00:27:31,870 So we have our Contacts screen. 495 00:27:31,870 --> 00:27:33,940 We can toggle the contacts, which is just 496 00:27:33,940 --> 00:27:38,750 something in state that decides whether or not we should render this list. 497 00:27:38,750 --> 00:27:51,180 This list is just a Scroll View which maps over all the contacts 498 00:27:51,180 --> 00:27:54,305 that we passed it, and renders a row here. 499 00:27:54,305 --> 00:27:55,055 And what is a row? 500 00:27:55,055 --> 00:27:58,380 501 00:27:58,380 --> 00:28:05,940 Well, a row is just a very basic view with a couple Text things within it. 502 00:28:05,940 --> 00:28:09,860 And so let's first implement this change. 503 00:28:09,860 --> 00:28:13,310 And so we're going to need some way to tell our app, 504 00:28:13,310 --> 00:28:17,060 hey, we're going to do something here. 505 00:28:17,060 --> 00:28:19,730 And generally, when we're talking about a Redux app, when 506 00:28:19,730 --> 00:28:22,310 we want to tell our app to do something, and by do something, 507 00:28:22,310 --> 00:28:24,380 I mean change something in our state, we want 508 00:28:24,380 --> 00:28:26,684 to do that by dispatching an action. 509 00:28:26,684 --> 00:28:28,850 So let's first add an action for what we want to do. 510 00:28:28,850 --> 00:28:32,910 511 00:28:32,910 --> 00:28:34,830 So within our actions.js, which is where we 512 00:28:34,830 --> 00:28:38,110 define all of our action types and our action creators, 513 00:28:38,110 --> 00:28:43,830 let's add a new action type for changing the first user. 514 00:28:43,830 --> 00:28:53,219 515 00:28:53,219 --> 00:28:54,510 So we just added a action type. 516 00:28:54,510 --> 00:28:58,830 And now we are going to add a action creator, which is just 517 00:28:58,830 --> 00:29:02,780 a function that returns an action. 518 00:29:02,780 --> 00:29:05,040 And if we remember back to a couple lectures ago, 519 00:29:05,040 --> 00:29:11,870 an action is just an object with a type and maybe payload key. 520 00:29:11,870 --> 00:29:19,650 So let's export something called Change First Contact. 521 00:29:19,650 --> 00:29:21,290 It doesn't take any arguments. 522 00:29:21,290 --> 00:29:26,290 And it just returns an object with a type that is Change First User. 523 00:29:26,290 --> 00:29:27,540 Let me change this to Contact. 524 00:29:27,540 --> 00:29:38,650 525 00:29:38,650 --> 00:29:39,150 Cool. 526 00:29:39,150 --> 00:29:42,050 So we now have our action type. 527 00:29:42,050 --> 00:29:45,760 And so when we dispatch this type, we need some sort of thing 528 00:29:45,760 --> 00:29:51,960 that is listening and will change our data. 529 00:29:51,960 --> 00:29:53,620 And so we do that in the reducer. 530 00:29:53,620 --> 00:29:57,270 531 00:29:57,270 --> 00:30:01,460 And if you remember, our reducer right now 532 00:30:01,460 --> 00:30:03,460 is just built up of two smaller reducers. 533 00:30:03,460 --> 00:30:06,460 One handles the user part of the app. 534 00:30:06,460 --> 00:30:08,832 And one handles our contacts. 535 00:30:08,832 --> 00:30:10,540 And so since we're changing the contacts, 536 00:30:10,540 --> 00:30:14,920 we should update our contact reducer, which is up at the top here. 537 00:30:14,920 --> 00:30:17,340 We have a Contact Reducer. 538 00:30:17,340 --> 00:30:21,900 It's passed some state, which is initialized to our contacts 539 00:30:21,900 --> 00:30:23,560 in an action. 540 00:30:23,560 --> 00:30:27,222 And if our action type is Update Contact, we add a contact. 541 00:30:27,222 --> 00:30:28,930 And now we're going to add something that 542 00:30:28,930 --> 00:30:38,500 says if our action type is change first contact, 543 00:30:38,500 --> 00:30:40,460 then we should do something else. 544 00:30:40,460 --> 00:30:47,444 And let me remember to import that from our actions. 545 00:30:47,444 --> 00:30:48,860 And so what do we want to do here? 546 00:30:48,860 --> 00:30:54,940 We want to change our first contact and do that in a way that is immutable. 547 00:30:54,940 --> 00:30:57,340 Because if you remember back to the lecture on Redux, 548 00:30:57,340 --> 00:31:01,270 every time we change our state, we want to do that immutably. 549 00:31:01,270 --> 00:31:03,730 And so we needed to figure out a way to extract 550 00:31:03,730 --> 00:31:08,470 the first contact in our contacts list, change it somehow, and then add it back 551 00:31:08,470 --> 00:31:09,820 in. 552 00:31:09,820 --> 00:31:12,170 So how might we do that? 553 00:31:12,170 --> 00:31:16,940 Well, let's use some shorthand here. 554 00:31:16,940 --> 00:31:21,920 So just like there's shorthand to pull keys out of objects-- 555 00:31:21,920 --> 00:31:25,090 so say we wanted to get that action type. 556 00:31:25,090 --> 00:31:31,890 We could do something like this, which is basically 557 00:31:31,890 --> 00:31:34,860 declaring a new const called Type, and assigning it 558 00:31:34,860 --> 00:31:37,560 to the type key of the action object. 559 00:31:37,560 --> 00:31:41,370 We can also do some pattern matching on arrays. 560 00:31:41,370 --> 00:31:45,420 So we could do first contact. 561 00:31:45,420 --> 00:31:51,540 And the rest of the contact is equal to that array called state. 562 00:31:51,540 --> 00:31:55,100 563 00:31:55,100 --> 00:32:03,650 So in other words, if state were something like name Jordan, 564 00:32:03,650 --> 00:32:09,860 phone some phone and there are no other people 565 00:32:09,860 --> 00:32:13,730 in this array, what would happen is first contact would 566 00:32:13,730 --> 00:32:16,670 match to Jordan to this object here. 567 00:32:16,670 --> 00:32:18,170 And the rest is just an empty array. 568 00:32:18,170 --> 00:32:26,720 And so we'd be left with First Contact is this object up here. 569 00:32:26,720 --> 00:32:30,680 And rest would be an empty array. 570 00:32:30,680 --> 00:32:37,170 And so this allows us to de-structure an array and assign it to a couple values. 571 00:32:37,170 --> 00:32:40,760 And so now that we have the first contact out, what we can do 572 00:32:40,760 --> 00:32:47,150 is the new contact is going to be an object because we're 573 00:32:47,150 --> 00:32:48,050 doing this immutably. 574 00:32:48,050 --> 00:32:50,420 We're creating a new object here. 575 00:32:50,420 --> 00:32:53,390 We can take the name. 576 00:32:53,390 --> 00:33:03,580 Or let's actually take all of the key value pairs of First Contact 577 00:33:03,580 --> 00:33:06,570 and just clone them. 578 00:33:06,570 --> 00:33:09,480 So if you remember what this dot, dot, dot notation is doing 579 00:33:09,480 --> 00:33:14,100 is it's saying take all of the key value pairs in an array in an object called 580 00:33:14,100 --> 00:33:15,870 First Contact. 581 00:33:15,870 --> 00:33:20,760 And put them into this new object that we've just created here. 582 00:33:20,760 --> 00:33:26,890 And so this effectively immutably makes a copy of First Contact. 583 00:33:26,890 --> 00:33:31,120 And now let's overwrite the name and say the name is just going to be my name. 584 00:33:31,120 --> 00:33:34,250 585 00:33:34,250 --> 00:33:36,710 So now we've immutably updated a new contact 586 00:33:36,710 --> 00:33:39,560 so that it's a clone of the first contact. 587 00:33:39,560 --> 00:33:41,620 But we're overwriting the property called name 588 00:33:41,620 --> 00:33:44,910 and replacing it with my name. 589 00:33:44,910 --> 00:33:48,170 And now let's return some new state. 590 00:33:48,170 --> 00:33:49,550 And what is the new state? 591 00:33:49,550 --> 00:33:53,690 Well, the First Contact is actually going to be the new contact here. 592 00:33:53,690 --> 00:33:59,470 And then the rest are just going to be whatever was there before. 593 00:33:59,470 --> 00:34:02,000 And so a quick recap of what's going on here 594 00:34:02,000 --> 00:34:07,250 is the state comes down as whatever the state used to be. 595 00:34:07,250 --> 00:34:11,087 We're matching on the type, Change First Contact. 596 00:34:11,087 --> 00:34:12,920 And then we're using this shorthand in order 597 00:34:12,920 --> 00:34:18,989 to grab the first contact in our list. 598 00:34:18,989 --> 00:34:23,960 We're just assigning the rest into this variable just to hold them for now. 599 00:34:23,960 --> 00:34:25,940 And then we're modifying new contact. 600 00:34:25,940 --> 00:34:27,440 And we're doing that immutably. 601 00:34:27,440 --> 00:34:33,219 And so we're creating a new object by using this object literal notation. 602 00:34:33,219 --> 00:34:36,752 We're copying over all of the key value pairs of the First Contact. 603 00:34:36,752 --> 00:34:38,710 And then we're going to overwrite one of those. 604 00:34:38,710 --> 00:34:41,270 And so we're overwriting the name. 605 00:34:41,270 --> 00:34:43,550 And we're changing it to my name. 606 00:34:43,550 --> 00:34:49,296 And then lastly, we are returning a new contact with the rest. 607 00:34:49,296 --> 00:34:51,170 And then we can make this a little bit safer. 608 00:34:51,170 --> 00:34:53,900 So say there are actually no contacts. 609 00:34:53,900 --> 00:35:00,470 Maybe if there's no First Contact, just return the state. 610 00:35:00,470 --> 00:35:05,100 So that just makes it a little bit safer in case there's nobody 611 00:35:05,100 --> 00:35:05,975 in the first contact. 612 00:35:05,975 --> 00:35:10,670 613 00:35:10,670 --> 00:35:11,170 Cool. 614 00:35:11,170 --> 00:35:17,110 So now we've added an action which notifies our reducer that we 615 00:35:17,110 --> 00:35:19,900 want to change our First Contact. 616 00:35:19,900 --> 00:35:24,620 We've added that logic in the reducer to actually change the first contact. 617 00:35:24,620 --> 00:35:27,580 And now we need to effectively fire that action off. 618 00:35:27,580 --> 00:35:31,010 And so how are we going to do that? 619 00:35:31,010 --> 00:35:36,700 Well, let's go into our screen and open our Contacts List screen. 620 00:35:36,700 --> 00:35:41,210 And so let's add a button here, which fires that off. 621 00:35:41,210 --> 00:35:47,850 And so let's import that action. 622 00:35:47,850 --> 00:35:53,510 We called it Change First Contact from our Redux actions. 623 00:35:53,510 --> 00:35:57,850 624 00:35:57,850 --> 00:36:06,240 Let's create a new button that says Change First Contact. 625 00:36:06,240 --> 00:36:13,211 And then all we have to do on press is just Change First Contact. 626 00:36:13,211 --> 00:36:13,710 Right? 627 00:36:13,710 --> 00:36:15,720 So now we go here. 628 00:36:15,720 --> 00:36:17,400 And we click Change First Contact. 629 00:36:17,400 --> 00:36:20,260 But nothing happens. 630 00:36:20,260 --> 00:36:22,420 So what is going wrong here? 631 00:36:22,420 --> 00:36:24,180 So let's just sanity check. 632 00:36:24,180 --> 00:36:29,684 So we import Change First Contact from our Redux actions. 633 00:36:29,684 --> 00:36:30,975 So let's go see what that does. 634 00:36:30,975 --> 00:36:34,520 635 00:36:34,520 --> 00:36:39,910 So Change First Contact here is a function that takes no arguments. 636 00:36:39,910 --> 00:36:42,481 And so when we click the button, it's invoking this function 637 00:36:42,481 --> 00:36:43,230 with no arguments. 638 00:36:43,230 --> 00:36:45,100 So that's all good. 639 00:36:45,100 --> 00:36:49,510 And then it returns an object that has a type key that 640 00:36:49,510 --> 00:36:52,480 is equal to Change First Contact. 641 00:36:52,480 --> 00:36:53,980 And so what is our bug here? 642 00:36:53,980 --> 00:36:57,370 Why is nothing happening when I'm clicking Change First Contact? 643 00:36:57,370 --> 00:37:01,180 Well, all that's actually happening is we're invoking 644 00:37:01,180 --> 00:37:03,670 a function that returns an object. 645 00:37:03,670 --> 00:37:07,060 But nowhere is that letting our Redux store 646 00:37:07,060 --> 00:37:09,250 know that it should be dispatching an action. 647 00:37:09,250 --> 00:37:13,720 And so how do we bind that function-- that action creator-- 648 00:37:13,720 --> 00:37:16,990 to our dispatch function? 649 00:37:16,990 --> 00:37:21,640 The answer to that question is by using React Redux. 650 00:37:21,640 --> 00:37:28,040 And so if we go open up our Contact List screen, 651 00:37:28,040 --> 00:37:32,770 we see that we've already imported that connect higher order 652 00:37:32,770 --> 00:37:34,840 component from React Redux. 653 00:37:34,840 --> 00:37:40,030 We're already using it down here by mapping our state to our props. 654 00:37:40,030 --> 00:37:45,016 And now we just need to say also bind our action creators to our dispatch. 655 00:37:45,016 --> 00:37:46,390 And which one do we want to bind? 656 00:37:46,390 --> 00:37:48,505 Well, it's the one called Change First Contact. 657 00:37:48,505 --> 00:37:51,300 658 00:37:51,300 --> 00:37:54,910 And so that is now binding our action creator called Change First 659 00:37:54,910 --> 00:37:59,470 Contact to a prop that is passed down called Change First Contact, 660 00:37:59,470 --> 00:38:01,260 which is a function. 661 00:38:01,260 --> 00:38:05,380 And so here rather than invoking the action that we imported from 662 00:38:05,380 --> 00:38:09,085 our actions file, which is really just a function that returns an object, 663 00:38:09,085 --> 00:38:13,750 we want to invoke this .props.changefirstcontact 664 00:38:13,750 --> 00:38:17,350 because that's the one that's actually bound to our dispatch function. 665 00:38:17,350 --> 00:38:20,000 666 00:38:20,000 --> 00:38:23,860 And so if we save that and click this, we 667 00:38:23,860 --> 00:38:27,080 see that it did change the first contact. 668 00:38:27,080 --> 00:38:28,520 And we can do it again. 669 00:38:28,520 --> 00:38:30,420 And it has changed the contact again. 670 00:38:30,420 --> 00:38:32,920 But it doesn't really matter because we're changing the name 671 00:38:32,920 --> 00:38:35,530 from Jordan Hayashi to Jordan Hayashi. 672 00:38:35,530 --> 00:38:38,810 And we see that it takes a little bit of time. 673 00:38:38,810 --> 00:38:41,770 So let's refresh our app real quick. 674 00:38:41,770 --> 00:38:44,500 It takes a little bit of time to actually do 675 00:38:44,500 --> 00:38:48,370 that because it's changing this and then re-rendering our entire list. 676 00:38:48,370 --> 00:38:50,770 We can make that even more obvious if we up the number 677 00:38:50,770 --> 00:38:56,540 of contacts that are being displayed. 678 00:38:56,540 --> 00:38:59,110 So let's just open up the contacts file. 679 00:38:59,110 --> 00:39:04,350 Change 1,000 here to 5,000. 680 00:39:04,350 --> 00:39:08,707 And now it's rendering as we speak. 681 00:39:08,707 --> 00:39:10,290 And now it's taking quite a long time. 682 00:39:10,290 --> 00:39:15,990 And if we click this, we see it takes multiple seconds before it renders. 683 00:39:15,990 --> 00:39:18,040 And why is that happening? 684 00:39:18,040 --> 00:39:22,290 Well, when we click Change First Contact, what happens? 685 00:39:22,290 --> 00:39:25,704 It goes off to our Redux store and updates the first contact 686 00:39:25,704 --> 00:39:27,120 and then passes it back down here. 687 00:39:27,120 --> 00:39:28,530 And what happens? 688 00:39:28,530 --> 00:39:30,912 It renders that first contact with the new name. 689 00:39:30,912 --> 00:39:33,870 And then it renders the second contact with the exact same information. 690 00:39:33,870 --> 00:39:36,536 And it renders the third contact with the exact same information 691 00:39:36,536 --> 00:39:38,310 that hadn't changed from the last time. 692 00:39:38,310 --> 00:39:41,947 And so it's actually going down and re-rendering 5,000 people 693 00:39:41,947 --> 00:39:43,530 where really only one of them changed. 694 00:39:43,530 --> 00:39:48,720 We're extraneously re-rendering 4,999 contacts. 695 00:39:48,720 --> 00:39:50,160 And so let's try to optimize that. 696 00:39:50,160 --> 00:39:52,710 697 00:39:52,710 --> 00:39:55,920 So we know that we can use this thing called shouldComponentUpdate 698 00:39:55,920 --> 00:39:58,440 and or React PureComponent. 699 00:39:58,440 --> 00:40:03,210 And it basically just says, hey, if our props don't change, don't re-render me. 700 00:40:03,210 --> 00:40:05,800 And so how are we going to do that? 701 00:40:05,800 --> 00:40:08,320 Well, we want to do it in the row because rows the thing 702 00:40:08,320 --> 00:40:12,510 that's ultimately receiving the props. 703 00:40:12,510 --> 00:40:15,010 And right now, row is just a stateless functional component. 704 00:40:15,010 --> 00:40:21,660 It takes some props and returns an element. 705 00:40:21,660 --> 00:40:23,280 So let's actually make it stateful. 706 00:40:23,280 --> 00:40:26,730 And so by making it stateful, it can remember its old props 707 00:40:26,730 --> 00:40:30,510 and react accordingly. 708 00:40:30,510 --> 00:40:39,460 So let's actually do class row extends React.PureComponent. 709 00:40:39,460 --> 00:40:42,040 And so by using a PureComponent here, it's 710 00:40:42,040 --> 00:40:46,060 the same thing as a component with one thing changed. 711 00:40:46,060 --> 00:40:50,730 The shouldComponentUpdate lifecycle method is already implemented for us. 712 00:40:50,730 --> 00:40:53,230 And it's just does a shallow diff of the props. 713 00:40:53,230 --> 00:40:56,930 And so let's do that. 714 00:40:56,930 --> 00:41:02,635 Must have a render method that returned this. 715 00:41:02,635 --> 00:41:07,120 716 00:41:07,120 --> 00:41:13,250 And so all we changed is rewrote-- 717 00:41:13,250 --> 00:41:16,640 let's silence ESLint. 718 00:41:16,640 --> 00:41:23,270 719 00:41:23,270 --> 00:41:29,960 We wrote what used to be a pure functional component. 720 00:41:29,960 --> 00:41:34,424 And we changed it to a class component that extends React PureComponent. 721 00:41:34,424 --> 00:41:36,340 And if you actually looked at the lint errors, 722 00:41:36,340 --> 00:41:39,080 there's a error here where props is not actually 723 00:41:39,080 --> 00:41:43,730 defined because in a stateless component, what is props? 724 00:41:43,730 --> 00:41:45,385 It's actually this.props. 725 00:41:45,385 --> 00:41:49,050 And so we can actually create a variable called 726 00:41:49,050 --> 00:41:54,890 props, which is equal to this.props. 727 00:41:54,890 --> 00:41:58,360 So I can just do that rather than adding this in front of those other ones. 728 00:41:58,360 --> 00:42:05,300 And we can actually use the shorthand here and do const props equals this, 729 00:42:05,300 --> 00:42:08,260 or in other words, this we expect to be an object. 730 00:42:08,260 --> 00:42:10,740 We expect it to have a key called props. 731 00:42:10,740 --> 00:42:14,680 And so let's create a new constant, call it props, and assign it 732 00:42:14,680 --> 00:42:17,880 to the value of the key props. 733 00:42:17,880 --> 00:42:23,470 And so now, if we save this, now each one of the rows is a PureComponent. 734 00:42:23,470 --> 00:42:26,240 And again, it's taking a few seconds to render. 735 00:42:26,240 --> 00:42:30,520 But now for each row here, these are PureComponents. 736 00:42:30,520 --> 00:42:35,715 And so they're React components that have a shouldComponentUpdate lifecycle 737 00:42:35,715 --> 00:42:36,340 method defined. 738 00:42:36,340 --> 00:42:39,850 And what it's doing is it says, all right, when you pass me new props, 739 00:42:39,850 --> 00:42:43,270 let me see what my current props are and check to see 740 00:42:43,270 --> 00:42:45,690 if the new props are any different. 741 00:42:45,690 --> 00:42:47,800 And if they're not, I'm not going to re-render. 742 00:42:47,800 --> 00:42:48,970 And if they are, I will. 743 00:42:48,970 --> 00:42:53,215 And so now let's click that Change First Contact button and see what happens. 744 00:42:53,215 --> 00:42:56,120 745 00:42:56,120 --> 00:42:57,700 It was pretty instant. 746 00:42:57,700 --> 00:43:01,150 Again, let's refresh. 747 00:43:01,150 --> 00:43:07,180 It's going to take five or so seconds to render the entire list. 748 00:43:07,180 --> 00:43:10,150 And we see that when we click this button, 749 00:43:10,150 --> 00:43:13,157 this changes in much less than five seconds. 750 00:43:13,157 --> 00:43:14,240 And what's happening here? 751 00:43:14,240 --> 00:43:18,835 Well, one, it's dispatching that action off to a Redux store. 752 00:43:18,835 --> 00:43:20,490 It's changing the first contact. 753 00:43:20,490 --> 00:43:24,430 It's then passing those props back down to this component. 754 00:43:24,430 --> 00:43:28,360 And then it's re-rendering this component. 755 00:43:28,360 --> 00:43:31,600 And for each row, it's passing down those contacts. 756 00:43:31,600 --> 00:43:36,560 And for the first one, it sees, hey, my name's different, so let me re-render. 757 00:43:36,560 --> 00:43:39,280 And then the next one, it says, all right, is my name the same 758 00:43:39,280 --> 00:43:40,640 as it used to be? 759 00:43:40,640 --> 00:43:41,320 Yeah, it is. 760 00:43:41,320 --> 00:43:43,360 Is my phone number the same as it used to be? 761 00:43:43,360 --> 00:43:44,470 Yes, it is. 762 00:43:44,470 --> 00:43:46,360 So now I don't need to re-render at all. 763 00:43:46,360 --> 00:43:50,830 Now I only need to just pass. 764 00:43:50,830 --> 00:43:56,320 And so it does have to do 5,000 equality checks-- 765 00:43:56,320 --> 00:43:57,760 one for each row. 766 00:43:57,760 --> 00:44:00,130 But the simple equality check there is much faster 767 00:44:00,130 --> 00:44:01,692 than re-rendering the component. 768 00:44:01,692 --> 00:44:04,850 769 00:44:04,850 --> 00:44:08,660 But what if we're passing props that we don't intend to pass. 770 00:44:08,660 --> 00:44:11,747 We're passing maybe much more than name and phone. 771 00:44:11,747 --> 00:44:13,580 And so we can actually optimize this further 772 00:44:13,580 --> 00:44:17,120 by saying we know that the only thing that might change 773 00:44:17,120 --> 00:44:21,440 is the name, really in this case. 774 00:44:21,440 --> 00:44:24,420 So we can actually optimize this further. 775 00:44:24,420 --> 00:44:28,160 So rather than doing a PureComponent, let's just do a normal component. 776 00:44:28,160 --> 00:44:30,590 And let's define our own shouldComponentUpdate. 777 00:44:30,590 --> 00:44:35,420 778 00:44:35,420 --> 00:44:39,590 And shouldComponentUpdate is passed the next props. 779 00:44:39,590 --> 00:44:42,130 780 00:44:42,130 --> 00:44:44,337 And we can check. 781 00:44:44,337 --> 00:44:47,420 Since I wrote the code, I know that the only thing I could possibly change 782 00:44:47,420 --> 00:44:48,560 is the name. 783 00:44:48,560 --> 00:45:00,530 So I can just check if the next props .name is different than the current 784 00:45:00,530 --> 00:45:01,370 props.name. 785 00:45:01,370 --> 00:45:06,370 786 00:45:06,370 --> 00:45:07,370 I can return true-- 787 00:45:07,370 --> 00:45:10,980 788 00:45:10,980 --> 00:45:14,430 else I can return false. 789 00:45:14,430 --> 00:45:18,130 790 00:45:18,130 --> 00:45:24,170 Or in other words, just return the value of this Boolean expression here. 791 00:45:24,170 --> 00:45:26,780 So instead of saying, if this is true, return true-- 792 00:45:26,780 --> 00:45:35,830 otherwise, return false, I can just say return next props.name is not equal 793 00:45:35,830 --> 00:45:37,792 to this props-- .props.name. 794 00:45:37,792 --> 00:45:42,420 795 00:45:42,420 --> 00:45:46,590 So if we now run this, it again takes five or so seconds 796 00:45:46,590 --> 00:45:50,250 in order to render the first time. 797 00:45:50,250 --> 00:45:54,060 But now when we want to change the first contact, that's actually 798 00:45:54,060 --> 00:45:57,330 roughly twice as fast as the previous one because instead 799 00:45:57,330 --> 00:46:01,895 of doing 5,000 checks where each check is checking every single prop, 800 00:46:01,895 --> 00:46:03,270 it's only checking a single prop. 801 00:46:03,270 --> 00:46:05,190 It's only checking name. 802 00:46:05,190 --> 00:46:08,280 And so by defining a shouldComponentUpdate, 803 00:46:08,280 --> 00:46:10,620 we save our component from re-rendering too often. 804 00:46:10,620 --> 00:46:15,450 805 00:46:15,450 --> 00:46:17,310 So what's next in our common inefficiencies? 806 00:46:17,310 --> 00:46:20,740 Well, unnecessarily changing props-- 807 00:46:20,740 --> 00:46:24,750 and so what might actually happen here is we accidentally or maybe not 808 00:46:24,750 --> 00:46:28,740 accidentally-- unknowingly-- change a value that is passed to a child 809 00:46:28,740 --> 00:46:31,470 and cause a re-render of the entire subtree. 810 00:46:31,470 --> 00:46:36,305 And so if you remember, the way that a React app is expressed 811 00:46:36,305 --> 00:46:39,850 is it's just a tree of a bunch of nodes. 812 00:46:39,850 --> 00:46:43,020 So we have our app. 813 00:46:43,020 --> 00:46:45,615 And then maybe our app has a couple different components. 814 00:46:45,615 --> 00:46:48,790 And maybe this one has a few different components. 815 00:46:48,790 --> 00:46:52,200 And maybe each of these has a few, and so on. 816 00:46:52,200 --> 00:46:54,850 817 00:46:54,850 --> 00:46:58,960 And so every single time we pass down new props, 818 00:46:58,960 --> 00:47:01,840 the entire subtree is updated, or could be updated 819 00:47:01,840 --> 00:47:03,730 depending on how it's implemented. 820 00:47:03,730 --> 00:47:07,890 And say these two things are PureComponents-- 821 00:47:07,890 --> 00:47:11,767 PureComponents-- PureComponent. 822 00:47:11,767 --> 00:47:12,600 So now what happens? 823 00:47:12,600 --> 00:47:15,390 If we pass down props that haven't changed, 824 00:47:15,390 --> 00:47:22,200 then the re-rendering is stopped there. 825 00:47:22,200 --> 00:47:26,550 So again, if app updates its state but the things 826 00:47:26,550 --> 00:47:28,642 that these two nodes rely on-- 827 00:47:28,642 --> 00:47:31,350 those props don't change since they're PureComponents-- they say, 828 00:47:31,350 --> 00:47:32,470 OK, I'm good. 829 00:47:32,470 --> 00:47:34,530 I don't need to update. 830 00:47:34,530 --> 00:47:38,910 But say we accidentally change one of those props, 831 00:47:38,910 --> 00:47:42,090 and we pass a new prop down to this? 832 00:47:42,090 --> 00:47:46,500 Then the PureComponent says, oh, I was updated, or one of my props at least 833 00:47:46,500 --> 00:47:47,320 changed. 834 00:47:47,320 --> 00:47:49,660 So now let me re-render everything below me. 835 00:47:49,660 --> 00:47:52,800 And so if we accidentally pass a prop that shouldn't have changed, 836 00:47:52,800 --> 00:47:56,370 but actually changes, then we are at the risk 837 00:47:56,370 --> 00:47:59,818 of re-rendering an entire subtree when we don't necessarily need to. 838 00:47:59,818 --> 00:48:06,040 839 00:48:06,040 --> 00:48:08,850 And so this is something that we see all the time. 840 00:48:08,850 --> 00:48:12,750 So say we have an object, or an array, or a function, or anything 841 00:48:12,750 --> 00:48:16,200 that can be expressed as a literal, say we have 842 00:48:16,200 --> 00:48:19,020 an object literal in our render method. 843 00:48:19,020 --> 00:48:21,270 That means every single time this component 844 00:48:21,270 --> 00:48:24,210 is rendered, a new object is created, just because it's 845 00:48:24,210 --> 00:48:28,030 an object literal in that sense. 846 00:48:28,030 --> 00:48:33,470 So this means we might be rendering something that we don't intend to. 847 00:48:33,470 --> 00:48:41,620 And so let's take a look at an example that has this side effect. 848 00:48:41,620 --> 00:48:43,830 So let's implement something called a Pure Button. 849 00:48:43,830 --> 00:48:46,855 850 00:48:46,855 --> 00:48:48,480 And we'll only use this for an example. 851 00:48:48,480 --> 00:48:51,990 All it is is it's going to be a button that will change colors 852 00:48:51,990 --> 00:48:53,670 if its props are changed. 853 00:48:53,670 --> 00:48:57,480 So let's just import React from React. 854 00:48:57,480 --> 00:49:03,845 Let's import Button from React Native. 855 00:49:03,845 --> 00:49:06,650 856 00:49:06,650 --> 00:49:09,850 And let's export a default-- 857 00:49:09,850 --> 00:49:20,212 a class called Pure Button, which extends React.PureComponent, 858 00:49:20,212 --> 00:49:21,920 which as we learned in the previous slide 859 00:49:21,920 --> 00:49:27,239 is just a component that we'll check to see if its props have been updating. 860 00:49:27,239 --> 00:49:28,280 If so, it will re-render. 861 00:49:28,280 --> 00:49:30,800 And if not, it actually won't. 862 00:49:30,800 --> 00:49:41,470 And let's just render and return a button 863 00:49:41,470 --> 00:49:43,350 where it just retains all of its props. 864 00:49:43,350 --> 00:49:48,390 865 00:49:48,390 --> 00:49:50,670 And let's actually do something additional. 866 00:49:50,670 --> 00:49:57,720 So let's have our state default to a color of null. 867 00:49:57,720 --> 00:50:02,100 And if the component updates-- 868 00:50:02,100 --> 00:50:06,700 so component did update-- 869 00:50:06,700 --> 00:50:11,690 let's set state and update that color to be something red. 870 00:50:11,690 --> 00:50:15,132 871 00:50:15,132 --> 00:50:16,840 And let's also pass this color down here. 872 00:50:16,840 --> 00:50:21,080 873 00:50:21,080 --> 00:50:23,600 So in other words, we have a button. 874 00:50:23,600 --> 00:50:25,740 Oh, and excuse this ESLint error. 875 00:50:25,740 --> 00:50:29,890 876 00:50:29,890 --> 00:50:33,540 So we have a component here, what we're calling a Pure Button. 877 00:50:33,540 --> 00:50:39,210 And all it does is it has a state which initializes as a null color. 878 00:50:39,210 --> 00:50:41,944 And so when it renders, it's just going to be a button. 879 00:50:41,944 --> 00:50:44,860 It's going to pass all of its props just straight through to a button. 880 00:50:44,860 --> 00:50:48,870 But it's also going to say, hey, I have a special color that at first, it's 881 00:50:48,870 --> 00:50:49,710 just null. 882 00:50:49,710 --> 00:50:51,300 It doesn't have a color. 883 00:50:51,300 --> 00:50:55,300 But if I ever update, I'm going to change myself to be red. 884 00:50:55,300 --> 00:51:01,980 And so this component here, it'll turn red if we accidentally update it. 885 00:51:01,980 --> 00:51:07,510 So let's now create a new screen. 886 00:51:07,510 --> 00:51:17,980 887 00:51:17,980 --> 00:51:20,030 Let's have a screen that-- 888 00:51:20,030 --> 00:51:26,020 let's just copy it from our Contact List screen. 889 00:51:26,020 --> 00:51:31,750 890 00:51:31,750 --> 00:51:38,220 So this screen is not going to have much. 891 00:51:38,220 --> 00:51:42,170 We can actually delete these things. 892 00:51:42,170 --> 00:51:47,490 Let's-- ah, it's probably going to be faster just to rewrite it. 893 00:51:47,490 --> 00:51:55,620 894 00:51:55,620 --> 00:51:56,580 So let's have a screen. 895 00:51:56,580 --> 00:51:57,829 First we need to import React. 896 00:51:57,829 --> 00:52:02,470 897 00:52:02,470 --> 00:52:08,830 We're going to import a View from React Native. 898 00:52:08,830 --> 00:52:16,430 899 00:52:16,430 --> 00:52:18,320 And that's render this view. 900 00:52:18,320 --> 00:52:24,664 901 00:52:24,664 --> 00:52:27,330 And since I'll be quick, I'm just going to put the style inline. 902 00:52:27,330 --> 00:52:35,141 903 00:52:35,141 --> 00:52:37,890 And what should we have happen when you click the Pure Button-- so 904 00:52:37,890 --> 00:52:45,750 let's first say the Pure Button is going to have some style that 905 00:52:45,750 --> 00:52:48,170 will align itself to be centered. 906 00:52:48,170 --> 00:52:51,820 907 00:52:51,820 --> 00:52:54,640 And on press, what should we do? 908 00:52:54,640 --> 00:52:57,210 909 00:52:57,210 --> 00:52:58,290 Let's have it count. 910 00:52:58,290 --> 00:53:06,870 911 00:53:06,870 --> 00:53:08,825 So we're going to need a count here. 912 00:53:08,825 --> 00:53:18,420 913 00:53:18,420 --> 00:53:21,930 So this class extends React component. 914 00:53:21,930 --> 00:53:26,477 It's going to be initialized with a state that starts at 0. 915 00:53:26,477 --> 00:53:28,560 So if you recognize this example, it's the example 916 00:53:28,560 --> 00:53:30,855 that we gave on almost the first day of class 917 00:53:30,855 --> 00:53:32,850 when we were discussing React Native. 918 00:53:32,850 --> 00:53:39,690 Let's have a render method which returns this. 919 00:53:39,690 --> 00:53:48,943 920 00:53:48,943 --> 00:53:50,690 And what's going to happen on press? 921 00:53:50,690 --> 00:53:57,680 Let's do this.setstate, and do the previous state, 922 00:53:57,680 --> 00:53:59,400 and then return the count plus 1. 923 00:53:59,400 --> 00:54:08,761 924 00:54:08,761 --> 00:54:09,760 And then close our View. 925 00:54:09,760 --> 00:54:13,300 926 00:54:13,300 --> 00:54:21,430 And in theory, every time we click the button, it should increment the count. 927 00:54:21,430 --> 00:54:25,410 And maybe we should actually show the count. 928 00:54:25,410 --> 00:54:34,070 So let's also import some Text and display it. 929 00:54:34,070 --> 00:54:43,180 930 00:54:43,180 --> 00:54:45,580 And let's also remember to import our Pure Button. 931 00:54:45,580 --> 00:54:50,380 932 00:54:50,380 --> 00:54:53,460 And that should close those errors. 933 00:54:53,460 --> 00:54:58,740 So, cool, we just implemented the app that we had on nearly day one. 934 00:54:58,740 --> 00:55:01,140 And let's go ahead and render it. 935 00:55:01,140 --> 00:55:06,590 936 00:55:06,590 --> 00:55:16,220 So import that Pure Button screen from Pure Button screen, and render it. 937 00:55:16,220 --> 00:55:20,250 938 00:55:20,250 --> 00:55:24,380 So now we have-- 939 00:55:24,380 --> 00:55:24,880 oop. 940 00:55:24,880 --> 00:55:27,872 941 00:55:27,872 --> 00:55:31,380 We forgot to give a title to our button. 942 00:55:31,380 --> 00:55:32,630 So let's go ahead and do that. 943 00:55:32,630 --> 00:55:42,180 944 00:55:42,180 --> 00:55:46,140 And now we have our thing, so we can increment the count if we click it. 945 00:55:46,140 --> 00:55:49,530 And it will increment that number in the top left when you click it. 946 00:55:49,530 --> 00:55:52,320 And uh-oh, our button turns red. 947 00:55:52,320 --> 00:55:57,370 But it's a PureComponent, so it shouldn't be re-updating. 948 00:55:57,370 --> 00:56:01,290 And so remember, if we have any object literals in our render method, 949 00:56:01,290 --> 00:56:05,070 it's creating those object literals every single time render is clicked, 950 00:56:05,070 --> 00:56:06,740 or render happens. 951 00:56:06,740 --> 00:56:10,200 And so since in our render here we have a Pure 952 00:56:10,200 --> 00:56:14,340 Button, every single time this render is created, 953 00:56:14,340 --> 00:56:18,140 this object is getting recreated. 954 00:56:18,140 --> 00:56:21,060 And if we remember back to day one, we are talking 955 00:56:21,060 --> 00:56:23,250 about things like a style sheet. 956 00:56:23,250 --> 00:56:30,270 And so we can go ahead and use a style sheet here, 957 00:56:30,270 --> 00:56:34,110 which will guarantee that it won't create a new object every single time 958 00:56:34,110 --> 00:56:35,376 we re-render. 959 00:56:35,376 --> 00:56:39,812 And so let's do const styles equals a style sheet.create, 960 00:56:39,812 --> 00:56:42,270 something you should be pretty familiar with at this point. 961 00:56:42,270 --> 00:56:48,140 962 00:56:48,140 --> 00:56:55,140 And let's have our button style be align Self center. 963 00:56:55,140 --> 00:57:01,680 964 00:57:01,680 --> 00:57:03,305 And then go ahead and use it down here. 965 00:57:03,305 --> 00:57:09,911 966 00:57:09,911 --> 00:57:10,410 Great. 967 00:57:10,410 --> 00:57:16,440 So now it's not going to create a new style object 968 00:57:16,440 --> 00:57:18,420 every single time we render. 969 00:57:18,420 --> 00:57:21,390 And so now, we can see that we click it. 970 00:57:21,390 --> 00:57:24,730 And uh-oh, it still turns red. 971 00:57:24,730 --> 00:57:30,210 So even though we changed our object that was getting recreated every time, 972 00:57:30,210 --> 00:57:34,380 we still have here a function literal. 973 00:57:34,380 --> 00:57:38,160 And since we have just a literal function definition here, 974 00:57:38,160 --> 00:57:42,410 it's actually recreating that function every single render method as well. 975 00:57:42,410 --> 00:57:44,670 And so every single time we render this Pure Button, 976 00:57:44,670 --> 00:57:46,110 we're passing down a new function. 977 00:57:46,110 --> 00:57:49,607 Even though it does the exact same thing, 978 00:57:49,607 --> 00:57:51,690 it's actually a completely new function reference. 979 00:57:51,690 --> 00:57:57,870 And so what we can do here is declare a class property. 980 00:57:57,870 --> 00:58:02,190 So you can say increment, and all it does 981 00:58:02,190 --> 00:58:11,710 is this.setState and takes the previous state 982 00:58:11,710 --> 00:58:14,530 and sets the count equal to the previous state's count. 983 00:58:14,530 --> 00:58:17,330 984 00:58:17,330 --> 00:58:17,890 And add 1. 985 00:58:17,890 --> 00:58:23,460 986 00:58:23,460 --> 00:58:28,580 And so now down here, rather than declaring a new function, 987 00:58:28,580 --> 00:58:30,750 we can actually just use this.increment. 988 00:58:30,750 --> 00:58:35,060 989 00:58:35,060 --> 00:58:36,920 And it's complaining. 990 00:58:36,920 --> 00:58:39,380 But now it will run if we click. 991 00:58:39,380 --> 00:58:40,110 Oh, good. 992 00:58:40,110 --> 00:58:42,640 It's not turning red. 993 00:58:42,640 --> 00:58:45,350 But that's strange because we still have a string 994 00:58:45,350 --> 00:58:48,080 that we're just declaring here. 995 00:58:48,080 --> 00:58:50,930 So why isn't PureComponent re-rendering even though we're 996 00:58:50,930 --> 00:58:52,430 declaring a new string literal here? 997 00:58:52,430 --> 00:58:55,072 998 00:58:55,072 --> 00:58:57,780 So if you remember all the way back to one of the first lectures, 999 00:58:57,780 --> 00:58:59,880 we talked about the JavaScript primitive types. 1000 00:58:59,880 --> 00:59:02,670 We talked about how there were numbers. 1001 00:59:02,670 --> 00:59:07,229 There were many other types, including strings. 1002 00:59:07,229 --> 00:59:08,520 And lastly, there were objects. 1003 00:59:08,520 --> 00:59:11,880 And anything that wasn't one of those primitives was an object. 1004 00:59:11,880 --> 00:59:17,820 And every object gets recreated when you-- 1005 00:59:17,820 --> 00:59:22,645 and so, sorry, the way that you compare these things when you compare them with 1006 00:59:22,645 --> 00:59:25,380 triple equals, objects-- their references-- 1007 00:59:25,380 --> 00:59:26,790 will be changed. 1008 00:59:26,790 --> 00:59:30,330 And so if we declare a new object and we want 1009 00:59:30,330 --> 00:59:34,740 to compare it by doing a triple equals, if it's a new object, 1010 00:59:34,740 --> 00:59:37,390 no matter what's inside of it, they're going to be different. 1011 00:59:37,390 --> 00:59:40,770 Whereas for the primitives, when you compare them with triple equals, 1012 00:59:40,770 --> 00:59:44,040 you're just seeing if their values are the same. 1013 00:59:44,040 --> 00:59:47,040 And so even though this is technically a new string that we've 1014 00:59:47,040 --> 00:59:49,640 gone ahead and created, when you compare those, 1015 00:59:49,640 --> 00:59:54,074 since it's the same exact string, the PureComponent will know, 1016 00:59:54,074 --> 00:59:54,990 oh, it's the same one. 1017 00:59:54,990 --> 00:59:57,090 I don't need to re-render here. 1018 00:59:57,090 --> 01:00:00,380 And so that's please this ESLint. 1019 01:00:00,380 --> 01:00:06,780 1020 01:00:06,780 --> 01:00:14,880 And now this does behave how we actually wanted it to. 1021 01:00:14,880 --> 01:00:15,680 And why is that? 1022 01:00:15,680 --> 01:00:17,770 Well, it's because the title isn't changing. 1023 01:00:17,770 --> 01:00:19,600 The styles we're not declaring inline. 1024 01:00:19,600 --> 01:00:23,220 We actually brought it out to a separate style object here. 1025 01:00:23,220 --> 01:00:27,630 And same thing with this function. 1026 01:00:27,630 --> 01:00:29,490 And you see it's no longer turning red. 1027 01:00:29,490 --> 01:00:33,410 1028 01:00:33,410 --> 01:00:35,044 And so the last common error-- 1029 01:00:35,044 --> 01:00:38,210 so the way that we fix this is by using constants, or methods, or properties 1030 01:00:38,210 --> 01:00:39,918 on the class instance, which we just saw. 1031 01:00:39,918 --> 01:00:42,420 1032 01:00:42,420 --> 01:00:45,840 So let's look at the last very common error that I see, 1033 01:00:45,840 --> 01:00:49,300 which is unnecessary logic in a mount or an update. 1034 01:00:49,300 --> 01:00:52,650 So this one is a lot more subtle than the others. 1035 01:00:52,650 --> 01:00:55,220 But adding class properties to an instance-- 1036 01:00:55,220 --> 01:00:59,580 so adding properties to that particular instance of a class instead of methods 1037 01:00:59,580 --> 01:01:00,990 on the class. 1038 01:01:00,990 --> 01:01:02,770 And why is this bad? 1039 01:01:02,770 --> 01:01:05,910 Well, properties are created at every single mount. 1040 01:01:05,910 --> 01:01:10,320 Whereas methods are created just once ever. 1041 01:01:10,320 --> 01:01:13,110 And so in other words, when we create something 1042 01:01:13,110 --> 01:01:19,830 like this, which is a class property, which is set equal to a function, 1043 01:01:19,830 --> 01:01:22,620 as I explained when we first talked about this syntax, 1044 01:01:22,620 --> 01:01:34,430 it's basically the same as doing a constructor here, invoking the super, 1045 01:01:34,430 --> 01:01:39,140 and then doing this.increment equals a function that does this. 1046 01:01:39,140 --> 01:01:43,490 1047 01:01:43,490 --> 01:01:48,770 So that means every single time this component is constructed, 1048 01:01:48,770 --> 01:01:53,720 it creates a new function and says to equal to this. 1049 01:01:53,720 --> 01:01:57,100 Whereas if we had instead done something like this. 1050 01:01:57,100 --> 01:02:01,110 1051 01:02:01,110 --> 01:02:02,330 This is a method. 1052 01:02:02,330 --> 01:02:07,550 And this method is only created once at the time of creating this module. 1053 01:02:07,550 --> 01:02:13,130 And so something like array.map isn't created every single time 1054 01:02:13,130 --> 01:02:14,451 we create a new array. 1055 01:02:14,451 --> 01:02:16,700 It's just something that lives on the array prototype. 1056 01:02:16,700 --> 01:02:18,590 And so it's only created once. 1057 01:02:18,590 --> 01:02:25,250 Whereas here, same thing-- if we implement-- increment-- as a method 1058 01:02:25,250 --> 01:02:29,870 here, it's only created once at the time of this module's creation, 1059 01:02:29,870 --> 01:02:35,450 rather than every single time this component gets mounted or created, 1060 01:02:35,450 --> 01:02:42,990 which is effectively what happens when we do this as a class property as such. 1061 01:02:42,990 --> 01:02:47,810 And so this is one of the things that might get you 1062 01:02:47,810 --> 01:02:56,274 because if you had actually done it as a class method like this, what happens? 1063 01:02:56,274 --> 01:02:57,440 There's actually a bug here. 1064 01:02:57,440 --> 01:02:59,450 And we've seen this bug many times. 1065 01:02:59,450 --> 01:03:03,350 We'll click, and we say, oh, this.setstate is not a function. 1066 01:03:03,350 --> 01:03:04,990 Why is it not a function? 1067 01:03:04,990 --> 01:03:09,830 Because what is this when increment gets invoked? 1068 01:03:09,830 --> 01:03:12,290 It's not this class. 1069 01:03:12,290 --> 01:03:14,012 Who knows what it is? 1070 01:03:14,012 --> 01:03:15,470 And so there's actually a bug here. 1071 01:03:15,470 --> 01:03:17,803 And so we actually do need to bind this to the instance. 1072 01:03:17,803 --> 01:03:21,320 And so this is actually a time where it might not 1073 01:03:21,320 --> 01:03:27,320 be worth implementing this small, small optimization. 1074 01:03:27,320 --> 01:03:29,700 In fact, you can't even do it in this case. 1075 01:03:29,700 --> 01:03:34,160 But there are cases where if you have something like render where every time 1076 01:03:34,160 --> 01:03:38,540 render is invoked, it's always going to be in the correct this context. 1077 01:03:38,540 --> 01:03:48,470 That way, we don't have to implement render as a class property. 1078 01:03:48,470 --> 01:03:52,890 So it's possible that we wanted to bind render to this class. 1079 01:03:52,890 --> 01:03:56,599 And we can do that by using this notation. 1080 01:03:56,599 --> 01:03:59,640 But since every time render's invoked, it's using the right this context, 1081 01:03:59,640 --> 01:04:01,110 we don't have to. 1082 01:04:01,110 --> 01:04:04,190 And so that is a small optimization. 1083 01:04:04,190 --> 01:04:10,256 But again, remember, there are trade-offs for all these optimizations. 1084 01:04:10,256 --> 01:04:10,880 And what is it? 1085 01:04:10,880 --> 01:04:15,130 Well, these performance optimizations come at complexity costs. 1086 01:04:15,130 --> 01:04:19,220 And often times, it's just not worth the cost of complexity and maintainability. 1087 01:04:19,220 --> 01:04:21,000 So don't forget. 1088 01:04:21,000 --> 01:04:24,122 Don't over optimize until a bottleneck is found. 1089 01:04:24,122 --> 01:04:25,830 So let's go ahead and take a quick break. 1090 01:04:25,830 --> 01:04:30,470 And then after the break, we're going to look at a specific optimization built 1091 01:04:30,470 --> 01:04:32,300 into React Native. 1092 01:04:32,300 --> 01:04:33,530 Hello, and welcome back. 1093 01:04:33,530 --> 01:04:36,290 So before the break, we were talking about performance and a few 1094 01:04:36,290 --> 01:04:38,830 of the common pitfalls in React. 1095 01:04:38,830 --> 01:04:43,280 And we ended with me reminding you that a lot of these pitfalls 1096 01:04:43,280 --> 01:04:45,359 are less performance. 1097 01:04:45,359 --> 01:04:46,900 But it's not necessarily a bad thing. 1098 01:04:46,900 --> 01:04:51,589 Oftentimes, optimization comes at a cost that is too great. 1099 01:04:51,589 --> 01:04:53,630 The complexity that you end up adding to your app 1100 01:04:53,630 --> 01:04:57,830 is not worth the marginal benefits that you get in terms of cost. 1101 01:04:57,830 --> 01:05:00,690 1102 01:05:00,690 --> 01:05:03,450 So let's talk about a time where often it actually does 1103 01:05:03,450 --> 01:05:05,420 matter to be as performant as possible. 1104 01:05:05,420 --> 01:05:07,250 And that's in animations. 1105 01:05:07,250 --> 01:05:09,440 And so if you remember back to Project 1, 1106 01:05:09,440 --> 01:05:12,410 we implemented what was a Pomodoro timer. 1107 01:05:12,410 --> 01:05:14,910 And so let's add a progress bar to that timer. 1108 01:05:14,910 --> 01:05:21,040 So this progress bar should show us how much time is left in the timer. 1109 01:05:21,040 --> 01:05:23,450 And so the animation that we're about to create 1110 01:05:23,450 --> 01:05:27,690 is going to require both the JavaScript and UI thread. 1111 01:05:27,690 --> 01:05:30,030 And so let's go ahead and do it. 1112 01:05:30,030 --> 01:05:31,500 So I have it running here. 1113 01:05:31,500 --> 01:05:34,550 So this is just a solution. 1114 01:05:34,550 --> 01:05:35,410 It has a work timer. 1115 01:05:35,410 --> 01:05:37,330 It'll switch to a break timer. 1116 01:05:37,330 --> 01:05:39,680 25 minutes is probably too long for us to sit here 1117 01:05:39,680 --> 01:05:42,020 and wait to see the progress bar go up. 1118 01:05:42,020 --> 01:05:44,100 So let's actually modify the code. 1119 01:05:44,100 --> 01:05:49,890 1120 01:05:49,890 --> 01:05:54,795 So the code is conveniently copied into the repo if you cloned it before class. 1121 01:05:54,795 --> 01:05:58,820 1122 01:05:58,820 --> 01:06:01,430 So let's actually first just take a quick look 1123 01:06:01,430 --> 01:06:03,690 at exactly what this is doing. 1124 01:06:03,690 --> 01:06:06,850 So for those of you who took a look at the solution 1125 01:06:06,850 --> 01:06:09,830 that I released a few weeks ago, this is basically 1126 01:06:09,830 --> 01:06:13,291 the exact same solution cut and pasted. 1127 01:06:13,291 --> 01:06:15,290 Well, let's just take a look at what it's doing. 1128 01:06:15,290 --> 01:06:18,310 And so an app, we declare a couple things. 1129 01:06:18,310 --> 01:06:21,545 We declare the defaults for our work minutes and break minutes. 1130 01:06:21,545 --> 01:06:28,930 So let's actually adjust those to be something like 0.1 minutes, 1131 01:06:28,930 --> 01:06:30,340 or 6 seconds each. 1132 01:06:30,340 --> 01:06:37,280 And so if we save that, we'll see that it got reset to 6 seconds each. 1133 01:06:37,280 --> 01:06:38,970 But here we have a couple things. 1134 01:06:38,970 --> 01:06:45,260 We have our state, which has a work time and break time where the work time 1135 01:06:45,260 --> 01:06:48,800 and break time are measured in seconds. 1136 01:06:48,800 --> 01:06:53,600 We then have something called time remaining, which is the same thing 1137 01:06:53,600 --> 01:06:55,340 but measured in milliseconds. 1138 01:06:55,340 --> 01:06:58,760 We have a flag that is letting us know if the timer's running 1139 01:06:58,760 --> 01:07:00,080 or if it's paused. 1140 01:07:00,080 --> 01:07:05,310 And we have a flag that lets us know if the active timers work or break. 1141 01:07:05,310 --> 01:07:07,640 When that component mounts, we create a new timer. 1142 01:07:07,640 --> 01:07:14,640 I created a timer class, set the state to be running, 1143 01:07:14,640 --> 01:07:18,680 and then every single time the timer ticks, 1144 01:07:18,680 --> 01:07:32,540 we pass this function called Update Time Remaining, which is declared here, 1145 01:07:32,540 --> 01:07:35,030 which just sets the state. 1146 01:07:35,030 --> 01:07:37,040 And it does a bunch of other stuff. 1147 01:07:37,040 --> 01:07:39,950 But let's go take a look at what the timer is-- 1148 01:07:39,950 --> 01:07:41,700 how it's implemented. 1149 01:07:41,700 --> 01:07:44,000 So let's look at the utils. 1150 01:07:44,000 --> 01:07:48,080 I created a timer class to encapsulate all of the logic for timing. 1151 01:07:48,080 --> 01:07:50,660 And so this timer takes a duration-- 1152 01:07:50,660 --> 01:07:53,510 how long the timer should be in milliseconds. 1153 01:07:53,510 --> 01:07:56,870 It takes what it should it do every time it ticks a function-- 1154 01:07:56,870 --> 01:07:57,990 a callback there-- 1155 01:07:57,990 --> 01:08:00,840 and what should it do when it hits 0. 1156 01:08:00,840 --> 01:08:05,000 And so it goes ahead and saves all of those values. 1157 01:08:05,000 --> 01:08:09,620 It then goes ahead and creates what should be the end time. 1158 01:08:09,620 --> 01:08:12,150 And it starts ticking. 1159 01:08:12,150 --> 01:08:14,420 And what happens at every single tick? 1160 01:08:14,420 --> 01:08:21,240 Well, if the end time is less than what it is now, then it means we're done. 1161 01:08:21,240 --> 01:08:23,420 So let's invoke the callback with 0. 1162 01:08:23,420 --> 01:08:26,010 Let's invoke that on end function. 1163 01:08:26,010 --> 01:08:28,410 Otherwise, it means we're still ticking. 1164 01:08:28,410 --> 01:08:32,149 So let's invoke the tick function with however much time we have remaining. 1165 01:08:32,149 --> 01:08:38,029 Let's figure out exactly what time it should be when we want to tick next. 1166 01:08:38,029 --> 01:08:41,930 And so by moduloing the time remaining by 1,000, 1167 01:08:41,930 --> 01:08:46,050 we get however many milliseconds that are left until the next second 1168 01:08:46,050 --> 01:08:48,590 or until the next tick should be. 1169 01:08:48,590 --> 01:08:54,740 Then we create a timeout to invoke the same exact tick function again 1170 01:08:54,740 --> 01:08:56,479 that amount of milliseconds later. 1171 01:08:56,479 --> 01:09:02,750 And so this accounts for any delays if the JavaScript thread was full, 1172 01:09:02,750 --> 01:09:05,436 or if there's some time drift or something like that. 1173 01:09:05,436 --> 01:09:07,310 And this makes sure that the next tick should 1174 01:09:07,310 --> 01:09:11,069 be as close to the second as possible. 1175 01:09:11,069 --> 01:09:13,229 And then we have some logic for handling stop. 1176 01:09:13,229 --> 01:09:18,090 But that's a little bit less relevant for right now. 1177 01:09:18,090 --> 01:09:19,649 And so let's go ahead-- 1178 01:09:19,649 --> 01:09:23,770 go back into our app. 1179 01:09:23,770 --> 01:09:29,380 And let's try to create a progress bar right here that 1180 01:09:29,380 --> 01:09:34,800 will just grow and grow to the full width by the time our timer gets to 0. 1181 01:09:34,800 --> 01:09:36,910 And so how are we going to do that? 1182 01:09:36,910 --> 01:09:40,689 Should we implement that in our app component? 1183 01:09:40,689 --> 01:09:41,279 Probably not. 1184 01:09:41,279 --> 01:09:42,640 It sounds like it should be something that's 1185 01:09:42,640 --> 01:09:44,290 encapsulated into its own component. 1186 01:09:44,290 --> 01:09:45,540 So let's go ahead and do that. 1187 01:09:45,540 --> 01:09:48,830 1188 01:09:48,830 --> 01:09:51,970 So let's create a progress bar. 1189 01:09:51,970 --> 01:09:55,550 1190 01:09:55,550 --> 01:09:58,310 And it's just going to first import React 1191 01:09:58,310 --> 01:10:05,160 from React, import probably a View, and maybe also 1192 01:10:05,160 --> 01:10:09,270 a style sheet from React Native. 1193 01:10:09,270 --> 01:10:12,540 1194 01:10:12,540 --> 01:10:22,250 And that's-- for now, just export empty View. 1195 01:10:22,250 --> 01:10:26,960 1196 01:10:26,960 --> 01:10:28,280 And that's imported into app. 1197 01:10:28,280 --> 01:10:36,160 1198 01:10:36,160 --> 01:10:39,750 All right, so we have our progress bar, which all it does is just render 1199 01:10:39,750 --> 01:10:41,430 an empty View. 1200 01:10:41,430 --> 01:10:43,410 And that's imported into-- 1201 01:10:43,410 --> 01:10:46,720 and use it into our app. 1202 01:10:46,720 --> 01:10:49,000 So we have our countdown. 1203 01:10:49,000 --> 01:10:51,502 And let's just put it directly below the countdown. 1204 01:10:51,502 --> 01:10:54,190 1205 01:10:54,190 --> 01:10:57,930 Yeah, we want the progress bar here. 1206 01:10:57,930 --> 01:10:58,630 Cool. 1207 01:10:58,630 --> 01:11:00,490 So nothing should've visibly changed. 1208 01:11:00,490 --> 01:11:04,120 It's just an empty View. 1209 01:11:04,120 --> 01:11:09,617 We can style it so that we are sure that it's actually appearing. 1210 01:11:09,617 --> 01:11:13,280 1211 01:11:13,280 --> 01:11:14,280 So maybe let's do-- 1212 01:11:14,280 --> 01:11:25,991 1213 01:11:25,991 --> 01:11:36,262 so let's have the progress bar just be a height of 10 and a width of 100. 1214 01:11:36,262 --> 01:11:37,220 And let's make it blue. 1215 01:11:37,220 --> 01:11:43,110 1216 01:11:43,110 --> 01:11:46,980 So now we should see a blue bar up here, which is not actually 1217 01:11:46,980 --> 01:11:53,295 happening because I need to actually use that style. 1218 01:11:53,295 --> 01:11:58,070 1219 01:11:58,070 --> 01:11:59,580 So now we see a blue bar appear. 1220 01:11:59,580 --> 01:12:03,700 And so we're going to want to have that bar increase in width 1221 01:12:03,700 --> 01:12:05,590 as our timer goes down. 1222 01:12:05,590 --> 01:12:09,520 And so what information are you going to need in order 1223 01:12:09,520 --> 01:12:12,170 to ensure that that happens? 1224 01:12:12,170 --> 01:12:13,790 So what information do we have? 1225 01:12:13,790 --> 01:12:18,069 We have the time here, which is the time remaining left. 1226 01:12:18,069 --> 01:12:20,110 That's probably going to be important information 1227 01:12:20,110 --> 01:12:22,485 because the bar's going to be a different width depending 1228 01:12:22,485 --> 01:12:25,090 on how much time is left. 1229 01:12:25,090 --> 01:12:28,450 We probably also want to know how much time there is total. 1230 01:12:28,450 --> 01:12:31,900 And so just having one second left doesn't really 1231 01:12:31,900 --> 01:12:35,800 give us enough information that we need to know how wide it should be. 1232 01:12:35,800 --> 01:12:38,530 So it needs to be one second left out of how many-- 1233 01:12:38,530 --> 01:12:41,620 out of the 6 seconds that were total for the work time. 1234 01:12:41,620 --> 01:12:47,140 So we need to know both the time left and the time total. 1235 01:12:47,140 --> 01:12:49,720 What else do we need to know? 1236 01:12:49,720 --> 01:12:50,960 Probably nothing else. 1237 01:12:50,960 --> 01:12:54,609 So let's go ahead and pass those props down to our progress bar 1238 01:12:54,609 --> 01:12:56,150 so that we can go ahead and use them. 1239 01:12:56,150 --> 01:13:02,170 1240 01:13:02,170 --> 01:13:04,975 So here, what do we have at our disposal? 1241 01:13:04,975 --> 01:13:07,910 1242 01:13:07,910 --> 01:13:10,300 We have work time and break time. 1243 01:13:10,300 --> 01:13:13,574 So we need to figure out exactly which one of those to use. 1244 01:13:13,574 --> 01:13:15,740 And we have time remaining, so that's already there. 1245 01:13:15,740 --> 01:13:19,650 So we can pass the time remaining into our progress bar. 1246 01:13:19,650 --> 01:13:27,015 1247 01:13:27,015 --> 01:13:32,974 Remaining-- and we want to have the total time. 1248 01:13:32,974 --> 01:13:34,015 Let's call it time Total. 1249 01:13:34,015 --> 01:13:37,652 1250 01:13:37,652 --> 01:13:39,610 So we need to figure out how to calculate that. 1251 01:13:39,610 --> 01:13:42,860 1252 01:13:42,860 --> 01:13:45,400 So let's just write a helper method here. 1253 01:13:45,400 --> 01:13:49,510 We can do get total-- 1254 01:13:49,510 --> 01:13:51,085 we get time Total. 1255 01:13:51,085 --> 01:13:56,776 1256 01:13:56,776 --> 01:13:57,900 And what is it going to do? 1257 01:13:57,900 --> 01:14:06,720 Well, let's get the work and break time, so const work time 1258 01:14:06,720 --> 01:14:11,690 is this.state.workTime is I believe what I called it. 1259 01:14:11,690 --> 01:14:12,190 Yep. 1260 01:14:12,190 --> 01:14:15,130 1261 01:14:15,130 --> 01:14:18,795 And const break time is this.state.breakTime. 1262 01:14:18,795 --> 01:14:22,857 1263 01:14:22,857 --> 01:14:24,690 So there's probably a better way to do this. 1264 01:14:24,690 --> 01:14:28,250 So the shorthand here is const workTime. 1265 01:14:28,250 --> 01:14:37,940 And breakTime is this.state, which is the shorthand for these two lines. 1266 01:14:37,940 --> 01:14:41,360 So we can just replace that. 1267 01:14:41,360 --> 01:14:45,800 And then we can return if this.state.-- 1268 01:14:45,800 --> 01:14:49,830 I think it's called active timer-- 1269 01:14:49,830 --> 01:15:06,640 yep-- if this.state.activetimer is work, return work time. 1270 01:15:06,640 --> 01:15:09,100 Otherwise, return break time. 1271 01:15:09,100 --> 01:15:12,970 So this helper method is just a simple function 1272 01:15:12,970 --> 01:15:16,600 that gets the work time and break time and returns the correct one depending 1273 01:15:16,600 --> 01:15:18,050 on what the active timer is. 1274 01:15:18,050 --> 01:15:22,090 And so that will get our total time. 1275 01:15:22,090 --> 01:15:24,210 So let's do this. 1276 01:15:24,210 --> 01:15:32,160 1277 01:15:32,160 --> 01:15:33,787 Let's do this.getTimeTotal. 1278 01:15:33,787 --> 01:15:36,600 1279 01:15:36,600 --> 01:15:40,640 And that will get the correct amount of time. 1280 01:15:40,640 --> 01:15:44,250 There's a potential bug here because that time is measured in seconds, 1281 01:15:44,250 --> 01:15:47,710 and this time is measured in milliseconds. 1282 01:15:47,710 --> 01:15:55,940 So let's get ahead of that by multiplying this by 1,000. 1283 01:15:55,940 --> 01:15:56,440 Cool. 1284 01:15:56,440 --> 01:16:02,594 So now get Time Total is in the same unit of time or measurement 1285 01:16:02,594 --> 01:16:03,510 as the time remaining. 1286 01:16:03,510 --> 01:16:06,350 Now they're both in milliseconds. 1287 01:16:06,350 --> 01:16:11,390 And maybe it might be helpful for this to know if it's running. 1288 01:16:11,390 --> 01:16:18,600 1289 01:16:18,600 --> 01:16:19,100 Cool. 1290 01:16:19,100 --> 01:16:22,460 So now let's go ahead and open up progress bar. 1291 01:16:22,460 --> 01:16:27,200 1292 01:16:27,200 --> 01:16:28,950 Let's actually use prop types here just so 1293 01:16:28,950 --> 01:16:31,080 that we can remember exactly what props we have. 1294 01:16:31,080 --> 01:16:48,500 1295 01:16:48,500 --> 01:16:51,200 So why did we pass? 1296 01:16:51,200 --> 01:17:00,240 We passed something called Time Total or Time Remaining, which is a number. 1297 01:17:00,240 --> 01:17:03,870 We passed Time Total, which is also a number. 1298 01:17:03,870 --> 01:17:07,910 And we also passed is running, which is a Boolean. 1299 01:17:07,910 --> 01:17:15,630 1300 01:17:15,630 --> 01:17:16,190 Cool. 1301 01:17:16,190 --> 01:17:18,130 So now we have a progress bar. 1302 01:17:18,130 --> 01:17:22,221 We're passing down the props that we want, which is just the time 1303 01:17:22,221 --> 01:17:22,720 remaining-- 1304 01:17:22,720 --> 01:17:24,480 Time Total when it's running. 1305 01:17:24,480 --> 01:17:28,930 And right now it's just showing a blue bar. 1306 01:17:28,930 --> 01:17:31,480 But there is a bug here. 1307 01:17:31,480 --> 01:17:33,156 Where? 1308 01:17:33,156 --> 01:17:34,890 Line 13. 1309 01:17:34,890 --> 01:17:36,790 At line 13. 1310 01:17:36,790 --> 01:17:37,960 I forgot an equals. 1311 01:17:37,960 --> 01:17:38,710 Thank you, Yowon. 1312 01:17:38,710 --> 01:17:41,560 1313 01:17:41,560 --> 01:17:45,040 And now, yeah, it's just a blue bar. 1314 01:17:45,040 --> 01:17:50,290 So how are we going to get that bar to show the correct width? 1315 01:17:50,290 --> 01:17:51,430 Probably some math. 1316 01:17:51,430 --> 01:17:53,450 So let's do some math. 1317 01:17:53,450 --> 01:17:56,890 So in React Native, there's actually a really easy way 1318 01:17:56,890 --> 01:17:58,940 to get the width of the window. 1319 01:17:58,940 --> 01:18:05,170 We can import dimensions from React Native. 1320 01:18:05,170 --> 01:18:09,130 And we can do some calculation here. 1321 01:18:09,130 --> 01:18:14,660 So before you return, let's figure out exactly how wide the window is. 1322 01:18:14,660 --> 01:18:24,730 So const width of the window is Dimensions.get the window width. 1323 01:18:24,730 --> 01:18:29,810 So this will get us the dimensions, which is both height and width. 1324 01:18:29,810 --> 01:18:33,010 So we can just do .width because that's the one that we want. 1325 01:18:33,010 --> 01:18:38,110 Or again, we can use that shorthand where we de-structure 1326 01:18:38,110 --> 01:18:40,700 and grab the width out of that object. 1327 01:18:40,700 --> 01:18:43,880 So now we have the total width of the window. 1328 01:18:43,880 --> 01:18:48,770 And if we wanted to, we can actually just pass that in directly. 1329 01:18:48,770 --> 01:18:56,690 1330 01:18:56,690 --> 01:19:00,420 So we have the width here. 1331 01:19:00,420 --> 01:19:02,083 Oh, I typed widow. 1332 01:19:02,083 --> 01:19:02,890 [LAUGHTER] 1333 01:19:02,890 --> 01:19:05,630 I now see why you were laughing. 1334 01:19:05,630 --> 01:19:09,324 We don't want the widow's width, which is kind of a funny statement. 1335 01:19:09,324 --> 01:19:10,740 We actually want the window width. 1336 01:19:10,740 --> 01:19:16,700 And so we do indeed get the correct width of the window there. 1337 01:19:16,700 --> 01:19:19,470 So now let's go ahead and do some math. 1338 01:19:19,470 --> 01:19:22,340 So we know exactly how much time is remaining. 1339 01:19:22,340 --> 01:19:24,930 We know how much time there is total. 1340 01:19:24,930 --> 01:19:30,020 And so we could figure out using some proportions exactly how much of that 1341 01:19:30,020 --> 01:19:31,950 width of the window we should take. 1342 01:19:31,950 --> 01:19:43,304 So let's do const percentage is just the time remaining over the time Total. 1343 01:19:43,304 --> 01:19:44,720 And I'm grabbing those from props. 1344 01:19:44,720 --> 01:19:48,151 1345 01:19:48,151 --> 01:19:48,650 Cool. 1346 01:19:48,650 --> 01:19:51,000 So now I have the width, and I have a percentage 1347 01:19:51,000 --> 01:19:53,120 of the width I want to actually take up. 1348 01:19:53,120 --> 01:20:01,220 And we can just do here the percent times the width. 1349 01:20:01,220 --> 01:20:06,370 And so hopefully, we should now have a timer where the width is 1350 01:20:06,370 --> 01:20:08,239 proportional to the time left. 1351 01:20:08,239 --> 01:20:10,280 Unfortunately, it's going in the wrong direction. 1352 01:20:10,280 --> 01:20:14,080 The way I had imagined it was just a progress bar that grows from the left 1353 01:20:14,080 --> 01:20:15,500 to the right. 1354 01:20:15,500 --> 01:20:20,590 So again, not that hard to do with math. 1355 01:20:20,590 --> 01:20:24,010 So that's the inverse of the width that we want. 1356 01:20:24,010 --> 01:20:29,500 So we actually want the width minus that. 1357 01:20:29,500 --> 01:20:33,030 1358 01:20:33,030 --> 01:20:36,440 Or we could do the inverse of the percent. 1359 01:20:36,440 --> 01:20:48,400 So 1 minus that is the percentage of time that has occurred. 1360 01:20:48,400 --> 01:20:51,490 And now we can see it grow from the left to the right, 1361 01:20:51,490 --> 01:20:53,344 just like I'd imagined it in my mind. 1362 01:20:53,344 --> 01:20:55,510 Unfortunately, the way that I imagined it in my mind 1363 01:20:55,510 --> 01:20:58,060 was also a little bit smoother than it is currently. 1364 01:20:58,060 --> 01:21:01,510 Right now, it's only happening once per tick. 1365 01:21:01,510 --> 01:21:07,720 So as the seconds count down, a big block of the progress is achieved. 1366 01:21:07,720 --> 01:21:09,850 So how might we optimize this? 1367 01:21:09,850 --> 01:21:13,429 How might we actually make it do what we want it to do? 1368 01:21:13,429 --> 01:21:14,470 Well, there's a few ways. 1369 01:21:14,470 --> 01:21:17,230 Maybe we should just make it tick more often. 1370 01:21:17,230 --> 01:21:20,310 And so we saw the code for the timer. 1371 01:21:20,310 --> 01:21:24,340 1372 01:21:24,340 --> 01:21:29,890 We see that the way that this calculates when the next tick should be 1373 01:21:29,890 --> 01:21:33,040 is it just mooulos by 1,000, meaning it's going to tick again 1374 01:21:33,040 --> 01:21:37,840 at the next 1,000-- the next second. 1375 01:21:37,840 --> 01:21:40,780 So we can make this number smaller and have it tick more often. 1376 01:21:40,780 --> 01:21:51,760 So that's declare a constant up here called tick duration. 1377 01:21:51,760 --> 01:21:54,940 And set it to a second at first. 1378 01:21:54,940 --> 01:21:59,810 So we can just replace this with the tick duration. 1379 01:21:59,810 --> 01:22:01,440 And now it'll do the same thing-- 1380 01:22:01,440 --> 01:22:03,880 1 per second. 1381 01:22:03,880 --> 01:22:09,570 We can say now the tick duration is going to be a half second. 1382 01:22:09,570 --> 01:22:14,630 And we'll see that it now does twice per second. 1383 01:22:14,630 --> 01:22:17,860 Let's make it go even faster-- 1384 01:22:17,860 --> 01:22:23,060 maybe 1/20 of a second. 1385 01:22:23,060 --> 01:22:25,760 Now it's going pretty dang smooth. 1386 01:22:25,760 --> 01:22:28,660 Let's actually just make it run at 60 FPS. 1387 01:22:28,660 --> 01:22:29,455 So let's just do-- 1388 01:22:29,455 --> 01:22:32,346 1389 01:22:32,346 --> 01:22:33,720 this would be one frame a second. 1390 01:22:33,720 --> 01:22:35,880 And let's actually just divide it by 60. 1391 01:22:35,880 --> 01:22:38,030 So now we have 60 FPS. 1392 01:22:38,030 --> 01:22:40,010 And dang, is that smooth. 1393 01:22:40,010 --> 01:22:41,371 So cool, we just got it. 1394 01:22:41,371 --> 01:22:41,870 Done. 1395 01:22:41,870 --> 01:22:43,520 Easy. 1396 01:22:43,520 --> 01:22:47,300 But there's not really much happening in this app. 1397 01:22:47,300 --> 01:22:48,860 It's just a timer that ticks. 1398 01:22:48,860 --> 01:22:51,357 But what if this app was actually doing other stuff? 1399 01:22:51,357 --> 01:22:52,190 What if it was busy? 1400 01:22:52,190 --> 01:22:57,800 What if the JavaScript thread once in a while would actually get full? 1401 01:22:57,800 --> 01:23:01,091 So let's actually write up a function that will randomly block the JavaScript 1402 01:23:01,091 --> 01:23:02,090 thread, because why not? 1403 01:23:02,090 --> 01:23:05,760 It'll stimulate a lot of work being done. 1404 01:23:05,760 --> 01:23:07,770 So let's go back into app. 1405 01:23:07,770 --> 01:23:10,800 Let's write a block statement. 1406 01:23:10,800 --> 01:23:15,630 1407 01:23:15,630 --> 01:23:19,320 You might recall this block statement when I demonstrated it in 1408 01:23:19,320 --> 01:23:21,810 maybe Lecture 1, was it? 1409 01:23:21,810 --> 01:23:31,450 But all we're going to do is say done time is the current date. 1410 01:23:31,450 --> 01:23:35,340 And let's make it block for 200 milliseconds-- 1411 01:23:35,340 --> 01:23:38,090 not that long-- a fifth of a second. 1412 01:23:38,090 --> 01:23:47,460 And so let's do while the day done now is less than the done time. 1413 01:23:47,460 --> 01:23:48,710 Don't do anything-- just loop. 1414 01:23:48,710 --> 01:23:51,640 1415 01:23:51,640 --> 01:24:08,340 And in the render, let's say if randomly, so flip a coin. 1416 01:24:08,340 --> 01:24:11,670 If it's heads, block. 1417 01:24:11,670 --> 01:24:16,490 1418 01:24:16,490 --> 01:24:19,650 And so now we'll see it's getting really jittery. 1419 01:24:19,650 --> 01:24:20,700 And why is that? 1420 01:24:20,700 --> 01:24:26,430 Well, this thing is ticking once every-- 1421 01:24:26,430 --> 01:24:28,560 close to 17 milliseconds. 1422 01:24:28,560 --> 01:24:32,290 And each render, there's a 50% chance that it's going 1423 01:24:32,290 --> 01:24:34,710 to block randomly for 200 milliseconds. 1424 01:24:34,710 --> 01:24:39,930 And so now we're seeing the progress bar get really janky. 1425 01:24:39,930 --> 01:24:41,540 It goes smoothly. 1426 01:24:41,540 --> 01:24:43,920 And then the JavaScript thread gets busy. 1427 01:24:43,920 --> 01:24:46,550 It blocks for 200 milliseconds, and then goes again. 1428 01:24:46,550 --> 01:24:51,310 And so we see what people refer to as jank. 1429 01:24:51,310 --> 01:24:55,212 And so how might we fix this? 1430 01:24:55,212 --> 01:24:56,920 Well, the current animation that we wrote 1431 01:24:56,920 --> 01:25:01,115 requires both the JavaScript and the UI thread to run. 1432 01:25:01,115 --> 01:25:01,990 And what's happening? 1433 01:25:01,990 --> 01:25:04,900 Well, it's sending messages over the bridge tens of times per second. 1434 01:25:04,900 --> 01:25:06,760 It's actually not cheap to do that. 1435 01:25:06,760 --> 01:25:10,131 Every single time we do that, we need to serialize 1436 01:25:10,131 --> 01:25:12,880 any of the information that needs to get sent to the other thread, 1437 01:25:12,880 --> 01:25:13,980 and back and forth. 1438 01:25:13,980 --> 01:25:17,160 That's happening 60 times per second. 1439 01:25:17,160 --> 01:25:19,600 That's quite a lot. 1440 01:25:19,600 --> 01:25:22,570 And blocking either thread will impact the user experience. 1441 01:25:22,570 --> 01:25:26,770 And as we see here, this is blocking the JavaScript thread, 1442 01:25:26,770 --> 01:25:30,920 even though it's ultimately should be running on the UI thread. 1443 01:25:30,920 --> 01:25:32,250 And it's causing some jank. 1444 01:25:32,250 --> 01:25:37,430 It's really actually hurting our user experience. 1445 01:25:37,430 --> 01:25:39,204 So how can we go about fixing this? 1446 01:25:39,204 --> 01:25:40,620 Well, this is React Native, right? 1447 01:25:40,620 --> 01:25:43,690 We have the React side, and we have the Native side, 1448 01:25:43,690 --> 01:25:46,000 so let's just implement the animation in Native. 1449 01:25:46,000 --> 01:25:46,909 Easy-peasy. 1450 01:25:46,909 --> 01:25:47,950 We all know Swift, right? 1451 01:25:47,950 --> 01:25:50,560 We all know Objective-C. We all know Java. 1452 01:25:50,560 --> 01:25:52,630 I don't. 1453 01:25:52,630 --> 01:25:56,480 So this requires knowing many other languages, which a lot of people don't. 1454 01:25:56,480 --> 01:26:01,190 And so this probably isn't the correct way to do things. 1455 01:26:01,190 --> 01:26:03,900 But what if we could declare the animation in JavaScript-- 1456 01:26:03,900 --> 01:26:07,960 we all know JavaScript-- and have it run on the Native thread? 1457 01:26:07,960 --> 01:26:09,192 That would be pretty cool. 1458 01:26:09,192 --> 01:26:10,900 And it turns out that's already possible. 1459 01:26:10,900 --> 01:26:13,690 And so there's this API called Animated. 1460 01:26:13,690 --> 01:26:16,510 This allows us to declare our computation in JavaScript, 1461 01:26:16,510 --> 01:26:20,620 and actually compute it on the Native thread. 1462 01:26:20,620 --> 01:26:23,480 So now the JavaScript thread no longer needs to compute anything. 1463 01:26:23,480 --> 01:26:26,770 So if this was a expensive computation, it 1464 01:26:26,770 --> 01:26:30,010 frees up the JavaScript thread to not have to do it. 1465 01:26:30,010 --> 01:26:32,680 And in addition, the JavaScript thread can be blocked, 1466 01:26:32,680 --> 01:26:34,640 and the animation will still run. 1467 01:26:34,640 --> 01:26:38,650 It will even run smoothly, though, there actually 1468 01:26:38,650 --> 01:26:41,110 is a small caveat to using this-- that we can't use 1469 01:26:41,110 --> 01:26:45,110 this Native driver for layout props. 1470 01:26:45,110 --> 01:26:50,560 But the API documentation is here if you want to take a look. 1471 01:26:50,560 --> 01:26:52,420 I'll allow you to go read the documentation. 1472 01:26:52,420 --> 01:26:56,720 But I'll do a quick demo on exactly what this looks like. 1473 01:26:56,720 --> 01:26:58,960 So currently, again, real quick, what's happening 1474 01:26:58,960 --> 01:27:01,100 is we're declaring this computation. 1475 01:27:01,100 --> 01:27:04,240 This computation is actually just doing a quick percentage. 1476 01:27:04,240 --> 01:27:07,080 It says how much time is there left? 1477 01:27:07,080 --> 01:27:08,740 How much time was there to begin with? 1478 01:27:08,740 --> 01:27:11,110 We know approximately the percentage. 1479 01:27:11,110 --> 01:27:14,830 We know exactly the percentage of what the progress bar should be. 1480 01:27:14,830 --> 01:27:16,250 We compute that in JavaScript. 1481 01:27:16,250 --> 01:27:18,910 We say, OK, the width should be this amount. 1482 01:27:18,910 --> 01:27:21,600 We know it should be this percentage of the way done. 1483 01:27:21,600 --> 01:27:22,850 So you can multiply those two. 1484 01:27:22,850 --> 01:27:27,380 And lo and behold, after all this math, we have the width that we want. 1485 01:27:27,380 --> 01:27:31,220 Then we send that width over to the Native. 1486 01:27:31,220 --> 01:27:35,770 It'll re-render that View so that the View's width is that width. 1487 01:27:35,770 --> 01:27:38,770 And good-- it's good to go, except for the fact 1488 01:27:38,770 --> 01:27:41,410 that our JavaScript thread is randomly blocking. 1489 01:27:41,410 --> 01:27:46,180 So now let's implement this such that it runs completely on the Native thread. 1490 01:27:46,180 --> 01:27:50,350 1491 01:27:50,350 --> 01:27:58,520 So let's just copy the progress bar to progress bar animated 1492 01:27:58,520 --> 01:28:01,250 and import the correct thing. 1493 01:28:01,250 --> 01:28:07,670 1494 01:28:07,670 --> 01:28:10,280 So now it's using the animated one. 1495 01:28:10,280 --> 01:28:14,580 It's still janky because we didn't actually change anything. 1496 01:28:14,580 --> 01:28:16,580 So now let's go ahead and use that new cool API. 1497 01:28:16,580 --> 01:28:19,982 1498 01:28:19,982 --> 01:28:21,690 So what is the first thing we need to do? 1499 01:28:21,690 --> 01:28:25,830 Well, we should probably import animated. 1500 01:28:25,830 --> 01:28:28,647 So now we have this really powerful animated API. 1501 01:28:28,647 --> 01:28:30,480 And so this gives us a few different things. 1502 01:28:30,480 --> 01:28:35,310 It gives us this thing called animated.timing. 1503 01:28:35,310 --> 01:28:39,570 And what that is it's a function, which you 1504 01:28:39,570 --> 01:28:42,220 can say use this value as a reference. 1505 01:28:42,220 --> 01:28:45,310 And so the Native thread is going to compute everything. 1506 01:28:45,310 --> 01:28:47,820 And it will store it in this particular value. 1507 01:28:47,820 --> 01:28:52,440 And as this value changes, again, all of this computation 1508 01:28:52,440 --> 01:28:56,100 is being done on the Native thread, but as it changes, 1509 01:28:56,100 --> 01:28:59,920 just tell me what you want me to do, and tell me how I should change it. 1510 01:28:59,920 --> 01:29:02,670 And so the way that we do that is we actually 1511 01:29:02,670 --> 01:29:05,492 use this animated.timing function. 1512 01:29:05,492 --> 01:29:08,700 So in order to do that, we can no longer use a stateless functional component 1513 01:29:08,700 --> 01:29:09,660 here. 1514 01:29:09,660 --> 01:29:12,250 So let's do make this a class. 1515 01:29:12,250 --> 01:29:25,060 1516 01:29:25,060 --> 01:29:26,460 So now it's a class. 1517 01:29:26,460 --> 01:29:32,070 It does the exact same thing, except props should really be this.props. 1518 01:29:32,070 --> 01:29:35,260 1519 01:29:35,260 --> 01:29:38,260 So quick easy way to fix that. 1520 01:29:38,260 --> 01:29:40,326 Again, it's doing the exact same thing. 1521 01:29:40,326 --> 01:29:41,200 It's a component now. 1522 01:29:41,200 --> 01:29:44,860 But that didn't really help us at all. 1523 01:29:44,860 --> 01:29:49,510 So how can we actually make this better? 1524 01:29:49,510 --> 01:29:55,300 So let's store in our state now this percentage. 1525 01:29:55,300 --> 01:29:59,580 1526 01:29:59,580 --> 01:30:03,372 That's going to be a new animated.value. 1527 01:30:03,372 --> 01:30:04,580 And let's just start it at 0. 1528 01:30:04,580 --> 01:30:07,370 1529 01:30:07,370 --> 01:30:13,160 So this is basically saying I'm going to store in my local state, 1530 01:30:13,160 --> 01:30:15,110 so only I need to know about this. 1531 01:30:15,110 --> 01:30:17,410 I'm going to store a value that starts at 0. 1532 01:30:17,410 --> 01:30:19,600 Eventually, it's going to get to another value. 1533 01:30:19,600 --> 01:30:20,825 Maybe the value's 100. 1534 01:30:20,825 --> 01:30:21,700 Maybe it's a million. 1535 01:30:21,700 --> 01:30:23,627 Maybe it's anything I want. 1536 01:30:23,627 --> 01:30:25,210 But for now, it's going to start at 0. 1537 01:30:25,210 --> 01:30:27,549 And I'm just declaring it as a new animated value 1538 01:30:27,549 --> 01:30:28,840 because it's subject to change. 1539 01:30:28,840 --> 01:30:32,890 It's going to be changed at a pretty high frequency. 1540 01:30:32,890 --> 01:30:35,840 And it's going to be computed all in the Native thread. 1541 01:30:35,840 --> 01:30:46,000 And so when this component mounts, I'm going to create a new animation. 1542 01:30:46,000 --> 01:30:52,050 I'm going to do this.animation is animated.timing. 1543 01:30:52,050 --> 01:30:55,270 1544 01:30:55,270 --> 01:30:56,670 And it takes a couple things. 1545 01:30:56,670 --> 01:30:59,530 We first want to tell it what value we want it to animate. 1546 01:30:59,530 --> 01:31:01,338 So it's going to be this.state.percent. 1547 01:31:01,338 --> 01:31:05,280 1548 01:31:05,280 --> 01:31:07,870 And it's going to take a configuration object. 1549 01:31:07,870 --> 01:31:09,120 And what does it want? 1550 01:31:09,120 --> 01:31:14,598 1551 01:31:14,598 --> 01:31:17,920 Well, it's going to want a value that it should eventually get to, so 1552 01:31:17,920 --> 01:31:20,470 starting at 0. 1553 01:31:20,470 --> 01:31:24,080 And it's eventually going to get to maybe 100. 1554 01:31:24,080 --> 01:31:28,510 Since we did percentage before, we can do percentage now. 1555 01:31:28,510 --> 01:31:30,010 So we're going to give it a toValue. 1556 01:31:30,010 --> 01:31:34,090 We can give it a 100. 1557 01:31:34,090 --> 01:31:37,000 It's also going to take a duration, so how long should it 1558 01:31:37,000 --> 01:31:39,370 be until it gets there. 1559 01:31:39,370 --> 01:31:45,170 Let's just do the duration is going to be however much time is remaining, 1560 01:31:45,170 --> 01:31:47,220 so this.props.timeRemaining. 1561 01:31:47,220 --> 01:31:50,860 1562 01:31:50,860 --> 01:31:55,510 And it's also going to take some sort of easing function, or in other words, 1563 01:31:55,510 --> 01:31:57,430 how quickly should this number go up and down? 1564 01:31:57,430 --> 01:32:01,420 So we could give it maybe a cubic if we wanted it to start slow and then 1565 01:32:01,420 --> 01:32:02,555 get really fast. 1566 01:32:02,555 --> 01:32:08,662 Or we could give it sine, or we can give it a quadratic exponential. 1567 01:32:08,662 --> 01:32:10,370 But really, we just want it to be linear, 1568 01:32:10,370 --> 01:32:14,006 so every millisecond that goes by is-- 1569 01:32:14,006 --> 01:32:15,880 so if a millisecond goes by at the beginning, 1570 01:32:15,880 --> 01:32:17,755 and a millisecond goes by in the middle, it's 1571 01:32:17,755 --> 01:32:20,250 going to increase by the same amount. 1572 01:32:20,250 --> 01:32:22,000 And so the easing function we want to give 1573 01:32:22,000 --> 01:32:25,470 it is going to be the linear function. 1574 01:32:25,470 --> 01:32:28,560 1575 01:32:28,560 --> 01:32:34,469 And so we're going to have to import easing from React Native, which 1576 01:32:34,469 --> 01:32:36,010 is built in and linked from the docs. 1577 01:32:36,010 --> 01:32:40,350 1578 01:32:40,350 --> 01:32:43,790 So now we have an animation. 1579 01:32:43,790 --> 01:32:45,180 It's not really doing anything. 1580 01:32:45,180 --> 01:32:48,140 We're starting it at 0. 1581 01:32:48,140 --> 01:32:51,570 The animation-- we store a reference to the animation. 1582 01:32:51,570 --> 01:32:53,160 It goes up to 100. 1583 01:32:53,160 --> 01:32:56,010 It's going to take as long as the time remaining. 1584 01:32:56,010 --> 01:32:59,090 And it's going to do it in a linear fashion. 1585 01:32:59,090 --> 01:33:00,600 But we should probably start it. 1586 01:33:00,600 --> 01:33:03,940 1587 01:33:03,940 --> 01:33:04,840 So, bam. 1588 01:33:04,840 --> 01:33:06,880 So now we have an animation. 1589 01:33:06,880 --> 01:33:09,480 It starts at 0. 1590 01:33:09,480 --> 01:33:11,740 It'll eventually get up to 100. 1591 01:33:11,740 --> 01:33:14,596 It's going to take the time remaining to get there. 1592 01:33:14,596 --> 01:33:16,720 And it's all going to happen on the Native threads. 1593 01:33:16,720 --> 01:33:22,030 So that number is going to scale from 0 to 100 at 60 FPS, presumably, 1594 01:33:22,030 --> 01:33:27,700 and is going to update that state and all compute on the Native thread. 1595 01:33:27,700 --> 01:33:29,800 So now what do we have to change here? 1596 01:33:29,800 --> 01:33:35,500 Well, unfortunately, there's a caveat of this Native driver. 1597 01:33:35,500 --> 01:33:37,000 It can't affect the layout props. 1598 01:33:37,000 --> 01:33:39,094 And so we can't actually change width. 1599 01:33:39,094 --> 01:33:40,510 We can't change the flex property. 1600 01:33:40,510 --> 01:33:41,610 We can't change height. 1601 01:33:41,610 --> 01:33:47,270 What we can do is we can actually scale the x dimension of our app. 1602 01:33:47,270 --> 01:33:49,540 So one thing I'm actually missing is it's not actually 1603 01:33:49,540 --> 01:33:51,790 running on the Native side. 1604 01:33:51,790 --> 01:33:53,830 So there's a prop that we need to pass called 1605 01:33:53,830 --> 01:34:02,440 use Native Driver True, which basically says, 1606 01:34:02,440 --> 01:34:05,319 hey, we can compute it on the JavaScript side, 1607 01:34:05,319 --> 01:34:07,110 but actually use the Native side for this-- 1608 01:34:07,110 --> 01:34:10,055 actually compute these things on the Native side. 1609 01:34:10,055 --> 01:34:13,920 So, Cool, now this is presumably going to update that state 1610 01:34:13,920 --> 01:34:16,420 value very quickly. 1611 01:34:16,420 --> 01:34:18,780 Now we can do down here-- 1612 01:34:18,780 --> 01:34:22,230 rather than scaling the width, let's actually transform it. 1613 01:34:22,230 --> 01:34:35,400 1614 01:34:35,400 --> 01:34:38,890 So let's do transformation. 1615 01:34:38,890 --> 01:34:43,300 Transform-- transform takes an array. 1616 01:34:43,300 --> 01:34:47,650 And the first one that we want to do is this transform or scale-- 1617 01:34:47,650 --> 01:34:49,812 scale x, I believe it's called. 1618 01:34:49,812 --> 01:34:52,217 Let me check my notes real quick. 1619 01:34:52,217 --> 01:34:55,110 1620 01:34:55,110 --> 01:34:56,690 It is called translate x. 1621 01:34:56,690 --> 01:35:04,970 1622 01:35:04,970 --> 01:35:07,010 I believe it's actually called scale x. 1623 01:35:07,010 --> 01:35:09,170 I'm not going to trust myself before. 1624 01:35:09,170 --> 01:35:13,520 And it's going to scale by this percent. 1625 01:35:13,520 --> 01:35:16,250 And this percent-- we're no longer computing it here. 1626 01:35:16,250 --> 01:35:19,730 It's actually going to be computed in the state-- 1627 01:35:19,730 --> 01:35:25,470 computed on the Native side and stored in this.state.percent value. 1628 01:35:25,470 --> 01:35:36,486 So now let's do transform is const percent is this.state. 1629 01:35:36,486 --> 01:35:38,200 We no longer use props. 1630 01:35:38,200 --> 01:35:42,110 And let's do percent times width. 1631 01:35:42,110 --> 01:35:44,850 So again, same thing. 1632 01:35:44,850 --> 01:35:46,620 Let's see if this works. 1633 01:35:46,620 --> 01:35:47,710 It's not going to. 1634 01:35:47,710 --> 01:35:50,350 And it's saying, oh, syntax error. 1635 01:35:50,350 --> 01:35:58,865 Unexpected token on line 38 because this needs to be an object. 1636 01:35:58,865 --> 01:36:03,450 1637 01:36:03,450 --> 01:36:10,110 It's not going to work because I'm not going to wait for it to bundle, 1638 01:36:10,110 --> 01:36:12,870 but it's because this is just a normal view. 1639 01:36:12,870 --> 01:36:15,390 And normal views can't actually get connected 1640 01:36:15,390 --> 01:36:19,120 to these animations that are being computed on the Native thread. 1641 01:36:19,120 --> 01:36:22,260 We actually need to use a special thing called 1642 01:36:22,260 --> 01:36:27,030 an animated view, which is just a view. 1643 01:36:27,030 --> 01:36:32,290 But it can watch these values that are being animated. 1644 01:36:32,290 --> 01:36:35,446 So let's go ahead and do this. 1645 01:36:35,446 --> 01:36:35,945 It crashed. 1646 01:36:35,945 --> 01:36:39,630 1647 01:36:39,630 --> 01:36:49,240 And as it reopens, I realize there's another bug here. 1648 01:36:49,240 --> 01:36:56,250 The width needs to start out at some number, so it can be scaled. 1649 01:36:56,250 --> 01:36:59,160 And I wonder if that was causing the crash. 1650 01:36:59,160 --> 01:37:02,930 Because you can't really scale a non-existent width. 1651 01:37:02,930 --> 01:37:04,984 Nope. 1652 01:37:04,984 --> 01:37:07,652 All right, debugging time. 1653 01:37:07,652 --> 01:37:11,130 1654 01:37:11,130 --> 01:37:13,450 So style takes styles.progress. 1655 01:37:13,450 --> 01:37:17,470 It also takes a transform, which maybe I should 1656 01:37:17,470 --> 01:37:19,210 trust myself and call this transform. 1657 01:37:19,210 --> 01:37:24,430 1658 01:37:24,430 --> 01:37:27,725 Translate x-- oh, this needs to take-- 1659 01:37:27,725 --> 01:37:35,380 1660 01:37:35,380 --> 01:37:38,810 OK, so I had the API incorrect in my mind. 1661 01:37:38,810 --> 01:37:40,580 It's scale x. 1662 01:37:40,580 --> 01:37:42,020 And it doesn't just take a number. 1663 01:37:42,020 --> 01:37:43,085 It takes a number-- 1664 01:37:43,085 --> 01:37:46,180 1665 01:37:46,180 --> 01:37:47,000 an input range. 1666 01:37:47,000 --> 01:37:51,320 1667 01:37:51,320 --> 01:37:58,850 OK, so what's really special about these animated values 1668 01:37:58,850 --> 01:38:03,140 is that it can interpolate itself and graph itself out on a line. 1669 01:38:03,140 --> 01:38:08,120 And so as the number grows, we can also tell it to map to a particular value. 1670 01:38:08,120 --> 01:38:10,040 And so percent right here is not a number, 1671 01:38:10,040 --> 01:38:13,070 so you can't just multiply percent by a number. 1672 01:38:13,070 --> 01:38:17,540 So what used to be percent.width times width doesn't work. 1673 01:38:17,540 --> 01:38:18,080 Why is that? 1674 01:38:18,080 --> 01:38:20,900 Because percent is not a normal number. 1675 01:38:20,900 --> 01:38:23,760 Percent is an animated.value. 1676 01:38:23,760 --> 01:38:26,426 And so you can't multiply an animated value by a number. 1677 01:38:26,426 --> 01:38:28,300 It's just going to crash your app, as we saw, 1678 01:38:28,300 --> 01:38:30,500 and which made me panic a second ago. 1679 01:38:30,500 --> 01:38:32,600 What we need to do is we need to interpolate 1680 01:38:32,600 --> 01:38:36,500 that animated value into a number. 1681 01:38:36,500 --> 01:38:41,905 And you do that by doing that value .interpolate. 1682 01:38:41,905 --> 01:38:49,330 1683 01:38:49,330 --> 01:38:51,810 And so by interpolating this value, we can say, OK, 1684 01:38:51,810 --> 01:38:55,810 this value is going to be a range from some number to some number. 1685 01:38:55,810 --> 01:38:59,930 And that should map onto some target range of some number to some number. 1686 01:38:59,930 --> 01:39:02,900 And it'll do the math automatically to get those proportions. 1687 01:39:02,900 --> 01:39:07,960 And so we know that the input range starts at 0. 1688 01:39:07,960 --> 01:39:10,360 And it goes to 100. 1689 01:39:10,360 --> 01:39:11,450 How do I know that? 1690 01:39:11,450 --> 01:39:14,050 Well, we declared that it starts at 0 here. 1691 01:39:14,050 --> 01:39:18,160 And we declared that it's eventually going to get to 100. 1692 01:39:18,160 --> 01:39:20,080 And what do we want to map it onto? 1693 01:39:20,080 --> 01:39:29,000 Well, the output range should start at 0. 1694 01:39:29,000 --> 01:39:30,890 And what do we want it to get to? 1695 01:39:30,890 --> 01:39:38,580 We eventually want it to get to the width of the application. 1696 01:39:38,580 --> 01:39:43,272 So now, hopefully, this won't crash our app 1697 01:39:43,272 --> 01:39:45,230 because we're no longer incorrectly multiplying 1698 01:39:45,230 --> 01:39:46,970 an animated value by a number. 1699 01:39:46,970 --> 01:39:50,720 We're instead taking that estimated value 1700 01:39:50,720 --> 01:39:54,920 and mapping it onto some value that starts at 0-- 1701 01:39:54,920 --> 01:39:56,990 ends at 100. 1702 01:39:56,990 --> 01:40:00,320 So that's the range of our animated value. 1703 01:40:00,320 --> 01:40:03,840 And we're mapping that onto some value that starts at 0 and ends at width. 1704 01:40:03,840 --> 01:40:07,850 And so we saw that it started at 0 and ends at exactly halfway through. 1705 01:40:07,850 --> 01:40:13,190 So the way that the scale is calculated is that we need to start at 0 1706 01:40:13,190 --> 01:40:16,310 and get to two times the width, or you can just make this 2. 1707 01:40:16,310 --> 01:40:19,380 1708 01:40:19,380 --> 01:40:24,100 And so now it scales correctly from 0 to the left all the way to 100. 1709 01:40:24,100 --> 01:40:27,730 And even though our app is still getting blocked by the JavaScript thread 1710 01:40:27,730 --> 01:40:29,460 as often as it was before-- 1711 01:40:29,460 --> 01:40:35,940 so we never removed that code in app.js that will randomly block-- 1712 01:40:35,940 --> 01:40:40,000 it's still blocking half the time, and half the time, every tick. 1713 01:40:40,000 --> 01:40:44,630 So very often, it's going to block randomly for 200 milliseconds. 1714 01:40:44,630 --> 01:40:49,210 But we see a completely smooth animation. 1715 01:40:49,210 --> 01:40:53,900 So there is no jank at all as it goes left to right. 1716 01:40:53,900 --> 01:41:00,550 And if we replace this with the non-animated progress bar, 1717 01:41:00,550 --> 01:41:06,410 we'll see that there is indeed jank as the JavaScript thread gets blocked. 1718 01:41:06,410 --> 01:41:07,390 So that's awesome. 1719 01:41:07,390 --> 01:41:16,320 We were able to with somewhat few bugs go ahead 1720 01:41:16,320 --> 01:41:19,830 and create this animated progress bar that does all the calculation 1721 01:41:19,830 --> 01:41:21,592 on the Native thread. 1722 01:41:21,592 --> 01:41:24,300 And so we see that even though the JavaScript thread is blocking, 1723 01:41:24,300 --> 01:41:27,130 this still works perfectly fine. 1724 01:41:27,130 --> 01:41:29,700 Unfortunately, it's not doing everything we want to. 1725 01:41:29,700 --> 01:41:33,540 When the break timer gets reset, the bar is just still full. 1726 01:41:33,540 --> 01:41:37,660 So let's go ahead and fix that. 1727 01:41:37,660 --> 01:41:43,315 So let's do component Will Receive Props. 1728 01:41:43,315 --> 01:41:48,730 1729 01:41:48,730 --> 01:41:52,250 And if we're resetting the timer-- so in other words, 1730 01:41:52,250 --> 01:41:59,050 if the next props.timeRemaining is greater than the current 1731 01:41:59,050 --> 01:42:07,190 props.timeRemaining, which will only happen when resetting the timer-- 1732 01:42:07,190 --> 01:42:08,870 then what do we want to do? 1733 01:42:08,870 --> 01:42:11,065 Well, let's do this.setState. 1734 01:42:11,065 --> 01:42:14,740 1735 01:42:14,740 --> 01:42:21,210 The percent is going to be a new Animated Value. 1736 01:42:21,210 --> 01:42:23,180 That starts at 0. 1737 01:42:23,180 --> 01:42:25,720 And then after that happens-- 1738 01:42:25,720 --> 01:42:29,200 so we need to make sure it resets the state. 1739 01:42:29,200 --> 01:42:31,900 We're going to restart this animation. 1740 01:42:31,900 --> 01:42:35,725 So let's change componentDidMount to be called startAnimation. 1741 01:42:35,725 --> 01:42:46,500 1742 01:42:46,500 --> 01:42:55,850 And when it mounts, let's go ahead and invoke this.startAnimation. 1743 01:42:55,850 --> 01:43:00,020 1744 01:43:00,020 --> 01:43:05,930 And then if we reset the timer, let's go ahead and reset the animated value. 1745 01:43:05,930 --> 01:43:08,090 And after that's done resetting, then go ahead 1746 01:43:08,090 --> 01:43:13,830 and pass a callback that will start the animation. 1747 01:43:13,830 --> 01:43:16,034 Because as we talked about in a prior lecture, 1748 01:43:16,034 --> 01:43:18,200 you can actually pass a callback to set state, which 1749 01:43:18,200 --> 01:43:22,550 will invoke after the state is set. 1750 01:43:22,550 --> 01:43:26,210 So now we see that as the timer goes down, 1751 01:43:26,210 --> 01:43:30,110 even though the JavaScript thread is randomly blocked, it's very smooth. 1752 01:43:30,110 --> 01:43:35,300 And when the timer gets reset, the animation gets reset. 1753 01:43:35,300 --> 01:43:37,346 And everything is good. 1754 01:43:37,346 --> 01:43:38,720 Unfortunately, we're out of time. 1755 01:43:38,720 --> 01:43:41,450 And so we won't go ahead and implement the pausing. 1756 01:43:41,450 --> 01:43:45,200 But hopefully, that has given you enough of a taste of the animated API 1757 01:43:45,200 --> 01:43:47,160 to go explore on your own. 1758 01:43:47,160 --> 01:43:47,660 So, great. 1759 01:43:47,660 --> 01:43:49,310 Thank you for joining us today. 1760 01:43:49,310 --> 01:43:51,050 And tomorrow for our final lecture, we'll 1761 01:43:51,050 --> 01:43:55,580 talk about deploying apps and maybe a little bit of testing. 1762 01:43:55,580 --> 01:43:57,430 Thank you. 1763 01:43:57,430 --> 01:43:58,759