1 00:00:06,630 --> 00:00:09,000 - In a functional component in React 2 00:00:09,000 --> 00:00:11,700 you can register code to be executed 3 00:00:11,700 --> 00:00:14,400 after each time the component is rendered. 4 00:00:14,400 --> 00:00:17,130 So, for example, after the component is rendered, 5 00:00:17,130 --> 00:00:19,350 you could write a message to the log file 6 00:00:19,350 --> 00:00:22,920 or you could send a message to a rest service. 7 00:00:22,920 --> 00:00:25,590 You could update some data in local storage, 8 00:00:25,590 --> 00:00:27,960 typically something non graphical 9 00:00:27,960 --> 00:00:30,831 that you want to do after each render has occurred. 10 00:00:30,831 --> 00:00:32,910 This is called an effect hook 11 00:00:32,910 --> 00:00:35,580 and this is how you do it in your component. 12 00:00:35,580 --> 00:00:40,530 You call React, useEffect, and you pass in a lambda, okay? 13 00:00:40,530 --> 00:00:43,800 And that lambda will be executed after each time 14 00:00:43,800 --> 00:00:47,520 the component is rendered to do some additional work, 15 00:00:47,520 --> 00:00:51,300 not graphical, but some additional non graphical work. 16 00:00:51,300 --> 00:00:53,910 And it'll happen after each rendering, 17 00:00:53,910 --> 00:00:55,170 if you write it like that. 18 00:00:55,170 --> 00:00:58,530 So after this component is rendered, each time, 19 00:00:58,530 --> 00:01:01,773 it'll output "hello" from this effect hook on the console. 20 00:01:01,773 --> 00:01:03,750 Okay? Right. 21 00:01:03,750 --> 00:01:06,780 So, there is another way of using Effect Hook. 22 00:01:06,780 --> 00:01:09,270 You can pass in an optional second parameter. 23 00:01:09,270 --> 00:01:11,820 You can pass in an array of dependencies 24 00:01:11,820 --> 00:01:14,820 such that the effect hook will only be invoked 25 00:01:14,820 --> 00:01:17,400 if one of those dependencies has changed. 26 00:01:17,400 --> 00:01:20,640 Have a look at this example. I've got a component. 27 00:01:20,640 --> 00:01:22,800 It calls React, useEffect. 28 00:01:22,800 --> 00:01:25,170 The first parameter is a lambda. 29 00:01:25,170 --> 00:01:27,896 This is the code that I'd like it to do, but only 30 00:01:27,896 --> 00:01:31,950 if either the minimum value or the maximum value changes. 31 00:01:31,950 --> 00:01:35,310 This is an array of dependencies. 32 00:01:35,310 --> 00:01:37,920 If either of these dependencies change, 33 00:01:37,920 --> 00:01:40,680 then this will be executed. 34 00:01:40,680 --> 00:01:42,780 Okay? But only if the minimum 35 00:01:42,780 --> 00:01:44,820 or the maximum value has changed. 36 00:01:44,820 --> 00:01:47,220 So that's conditional effect hook. 37 00:01:47,220 --> 00:01:49,230 Only execute that code if 38 00:01:49,230 --> 00:01:52,620 either the minimum value or the maximum value has changed 39 00:01:52,620 --> 00:01:54,453 since the last time it was rendered. 40 00:01:55,620 --> 00:01:58,710 Right? Well, I've got an example of effect hooks. 41 00:01:58,710 --> 00:02:01,854 If you go here, Enzyme_EffectHooks/demo-app, 42 00:02:01,854 --> 00:02:06,854 if you open that folder app in command window, 43 00:02:06,900 --> 00:02:11,550 NPM install, and then NPM run, NPM start, 44 00:02:11,550 --> 00:02:14,040 and there's a product list component. 45 00:02:14,040 --> 00:02:18,694 And the product list component receives a function called 46 00:02:18,694 --> 00:02:19,944 onRangeChanged. 47 00:02:20,847 --> 00:02:22,200 It's a callback function. 48 00:02:22,200 --> 00:02:23,670 And the idea is 49 00:02:23,670 --> 00:02:26,220 that the product list will basically define 50 00:02:26,220 --> 00:02:28,620 an effect hook such that, 51 00:02:28,620 --> 00:02:31,290 if the minimum value or the maximum value 52 00:02:31,290 --> 00:02:36,090 in state have changed, it will call that call back. 53 00:02:36,090 --> 00:02:40,563 So let's have a look at the code in product list. 54 00:02:42,960 --> 00:02:45,623 Here's my product list component. My product list, 55 00:02:45,623 --> 00:02:49,140 it receives an array of products. 56 00:02:49,140 --> 00:02:50,970 That's the first parameter. 57 00:02:50,970 --> 00:02:52,500 When you're using type script, 58 00:02:52,500 --> 00:02:55,100 you've gotta say the name of the parameter here 59 00:02:55,100 --> 00:02:58,500 or the name of the properties in there, and then colon, 60 00:02:58,500 --> 00:03:00,270 And then you've gotta give it type information 61 00:03:00,270 --> 00:03:01,500 for each property there. 62 00:03:01,500 --> 00:03:03,280 So it's a bit messy, 63 00:03:03,280 --> 00:03:05,616 but basically, what it's saying is, this function 64 00:03:05,616 --> 00:03:09,390 or this component, it receives a products property, 65 00:03:09,390 --> 00:03:12,303 an array of products, like that. 66 00:03:13,410 --> 00:03:14,340 That's the first property. 67 00:03:14,340 --> 00:03:16,857 And the second property is a callback function. 68 00:03:16,857 --> 00:03:18,480 And that callback function, 69 00:03:18,480 --> 00:03:22,680 it will invoke it, you know, under certain circumstances. 70 00:03:22,680 --> 00:03:25,110 That's the function that needs to be invoked. 71 00:03:25,110 --> 00:03:29,130 And that property there is a function 72 00:03:29,130 --> 00:03:31,650 that takes a string and returns void. 73 00:03:31,650 --> 00:03:33,960 You're basically specifying the signature of 74 00:03:33,960 --> 00:03:36,930 the callback function onRangeChanged, 75 00:03:36,930 --> 00:03:40,230 a function that takes a string doesn't return anything, 76 00:03:40,230 --> 00:03:41,640 presumably it will be just outputs 77 00:03:41,640 --> 00:03:44,040 that string on the console, something like that. 78 00:03:44,940 --> 00:03:46,680 Right? Well, let's talk like what's going on here. 79 00:03:46,680 --> 00:03:49,260 We we're basically setting up the minimum value 80 00:03:49,260 --> 00:03:51,453 and the maximum value in React state. 81 00:03:52,466 --> 00:03:56,940 If the user typed the value into a text box for the minimum, 82 00:03:56,940 --> 00:03:59,130 we update the minimum value in state, 83 00:03:59,130 --> 00:04:02,160 which would cause the component to be re-rendered. 84 00:04:02,160 --> 00:04:04,740 If the user types in a new value for the maximum, 85 00:04:04,740 --> 00:04:08,430 then get that value and send that value into React state 86 00:04:08,430 --> 00:04:12,090 to re-render with the new value for the maximum. 87 00:04:12,090 --> 00:04:16,590 Okay. So nothing new there, but this is the effect. 88 00:04:16,590 --> 00:04:18,120 This is my effect hook. 89 00:04:18,120 --> 00:04:20,370 This is the code that I want to execute, 90 00:04:20,370 --> 00:04:23,070 but only if the minimum value is changed 91 00:04:23,070 --> 00:04:25,500 or the maximum value is changed. 92 00:04:25,500 --> 00:04:29,490 So what it'll do is it says, potentially call this function 93 00:04:29,490 --> 00:04:33,903 after each render, but only if the minimum value 94 00:04:33,903 --> 00:04:37,650 or the maximum value or both have changed. 95 00:04:37,650 --> 00:04:40,354 So if the minimum value has changed or the maximum 96 00:04:40,354 --> 00:04:44,070 it'll basically invoke the callback onRangeChange as a 97 00:04:44,070 --> 00:04:46,020 as a callback function, it'll invoke it. 98 00:04:46,020 --> 00:04:48,016 And you'll say, oh, the range has changed. 99 00:04:48,016 --> 00:04:51,480 The value for the minimum is now something. 100 00:04:51,480 --> 00:04:53,520 And the value for the maximum is now something. 101 00:04:53,520 --> 00:04:57,120 It'll call that function back every time the minimum 102 00:04:57,120 --> 00:04:59,460 or the maximum value was changed. 103 00:04:59,460 --> 00:05:02,070 Okay. So think about this, now. 104 00:05:02,070 --> 00:05:03,480 Our product is component. 105 00:05:03,480 --> 00:05:06,150 When we run it from our top level app, 106 00:05:06,150 --> 00:05:08,160 we need to give it some kind of call back. 107 00:05:08,160 --> 00:05:12,215 We need to say what to do when the range changes. 108 00:05:12,215 --> 00:05:14,700 So let's see how we render that component 109 00:05:14,700 --> 00:05:16,380 from the top level. 110 00:05:16,380 --> 00:05:19,980 That's my app component, my application component. 111 00:05:19,980 --> 00:05:23,310 It says, render the product list, give it the products. 112 00:05:23,310 --> 00:05:25,380 Oh, and here is the callback function. 113 00:05:25,380 --> 00:05:27,900 That's the function it's gonna invoke back. 114 00:05:27,900 --> 00:05:30,120 Okay? So whenever the minimum value 115 00:05:30,120 --> 00:05:32,640 or the maximum value changes within the product list, 116 00:05:32,640 --> 00:05:34,908 it'll callback this function. 117 00:05:34,908 --> 00:05:38,070 And it'll just basically output on the log 118 00:05:38,070 --> 00:05:40,920 whatever we told it to, is calling that function 119 00:05:40,920 --> 00:05:44,820 with a string, which then gets echoed on the console. 120 00:05:44,820 --> 00:05:49,820 Okay. So it called my effect hook in product list. 121 00:05:50,190 --> 00:05:51,930 It called that call back. 122 00:05:51,930 --> 00:05:53,670 And it basically, you know, with this message 123 00:05:53,670 --> 00:05:55,320 the range has changed the minimum 124 00:05:55,320 --> 00:05:57,600 and the maximum are now this. 125 00:05:57,600 --> 00:05:58,620 Right. Well, that's interesting. 126 00:05:58,620 --> 00:06:00,270 Let's see what the application looks like. 127 00:06:00,270 --> 00:06:03,743 If you NPM install and then run the application 128 00:06:03,743 --> 00:06:05,070 let's see what it looks like. 129 00:06:05,070 --> 00:06:08,190 I'm gonna bring up the developer tools, 130 00:06:08,190 --> 00:06:10,020 F12 would do the same. 131 00:06:10,020 --> 00:06:12,990 And I'm gonna look in the console window. 132 00:06:12,990 --> 00:06:15,870 I'm hoping to see console messages appearing 133 00:06:15,870 --> 00:06:18,390 in here when the range has changed. 134 00:06:18,390 --> 00:06:21,780 So let's just clear the list there. 135 00:06:21,780 --> 00:06:25,495 I'm going to change the minimum to be five. 136 00:06:25,495 --> 00:06:28,500 Oh. So my product list realized 137 00:06:28,500 --> 00:06:32,880 that the minimum value had changed, and it called me back. 138 00:06:32,880 --> 00:06:35,340 The effect hook called back 139 00:06:35,340 --> 00:06:37,935 range changed minimum five maximum, 140 00:06:37,935 --> 00:06:40,110 the default maximum is a million, 141 00:06:40,110 --> 00:06:42,060 even though I hadn't typed in a million here, 142 00:06:42,060 --> 00:06:44,640 that's the default value for the maximum. 143 00:06:44,640 --> 00:06:48,688 If I type in a maximum of 500, now, 144 00:06:48,688 --> 00:06:50,760 the way I've written my application 145 00:06:50,760 --> 00:06:54,720 each keystroke is basically detected one by one. 146 00:06:54,720 --> 00:06:57,150 So if I type in 500 here, 147 00:06:57,150 --> 00:07:01,560 it generated the maximum value change to five. 148 00:07:01,560 --> 00:07:03,240 Then it changed to 50. 149 00:07:03,240 --> 00:07:04,920 Then it changed to 500. 150 00:07:04,920 --> 00:07:08,520 So it actually called my callback three times. 151 00:07:08,520 --> 00:07:11,340 Okay. So I could probably prove that, but 152 00:07:11,340 --> 00:07:12,570 but you get the idea? 153 00:07:12,570 --> 00:07:15,458 And if I change the minimum price to be 50, 154 00:07:15,458 --> 00:07:18,087 then it says the minimum price is like that. 155 00:07:18,087 --> 00:07:21,390 And if I get rid of the maximum price, 156 00:07:21,390 --> 00:07:24,090 then it'll default back to a million. 157 00:07:24,090 --> 00:07:25,920 And if I get rid of the minimum price, 158 00:07:25,920 --> 00:07:27,513 then it defaults back to zero. 159 00:07:28,470 --> 00:07:31,560 Okay? So these effect hooks are a useful mechanism 160 00:07:31,560 --> 00:07:32,820 in your component. 161 00:07:32,820 --> 00:07:35,070 You're doing the user interface logic, 162 00:07:35,070 --> 00:07:36,570 but there may be some, you know, 163 00:07:36,570 --> 00:07:38,760 you might want to do some additional work 164 00:07:38,760 --> 00:07:40,770 over and above the graphical user interface like, 165 00:07:40,770 --> 00:07:42,840 I'll put in log messages. 166 00:07:42,840 --> 00:07:44,160 So effect hooks give you a way 167 00:07:44,160 --> 00:07:46,983 of doing extra work after each rendering. 168 00:07:48,900 --> 00:07:53,900 Okay. So we can't, in our tests, directly interact 169 00:07:54,238 --> 00:07:56,040 with effect hooks, 170 00:07:56,040 --> 00:07:59,070 because they're entirely managed by React. 171 00:07:59,070 --> 00:08:01,110 But what we can do is to test 172 00:08:01,110 --> 00:08:03,810 that the callback function is invoked properly. 173 00:08:03,810 --> 00:08:08,810 We can say, assuming that an effect hook has been triggered, 174 00:08:09,330 --> 00:08:11,010 it should call me back, 175 00:08:11,010 --> 00:08:13,110 and it should call me back with this value. 176 00:08:13,110 --> 00:08:16,860 And that's what it means to test effect hooks in React. 177 00:08:16,860 --> 00:08:20,262 Check that the effect hook called some callback function 178 00:08:20,262 --> 00:08:23,523 with the appropriate parameters. 179 00:08:24,660 --> 00:08:27,197 Right. So have a look at this. 180 00:08:27,197 --> 00:08:30,660 I've basically, in my test harness, 181 00:08:30,660 --> 00:08:34,293 I've instantiated my component, 182 00:08:35,130 --> 00:08:38,190 but I've passed in a dummy callback function. 183 00:08:38,190 --> 00:08:40,650 So, you know, if the minimum value changes, 184 00:08:40,650 --> 00:08:42,240 or the maximum value changes, 185 00:08:42,240 --> 00:08:46,440 it's going to be calling this mock function, 186 00:08:48,990 --> 00:08:50,520 and I can check you know, 187 00:08:50,520 --> 00:08:52,770 what was that mock function invoked with? 188 00:08:52,770 --> 00:08:55,890 I can verify that the mock function was invoked 189 00:08:55,890 --> 00:08:57,240 with the correct string, 190 00:08:57,240 --> 00:09:00,180 the minimum value and the maximum value. 191 00:09:00,180 --> 00:09:02,540 So there's my mock callback function. 192 00:09:02,540 --> 00:09:05,490 And here is where I render my component, 193 00:09:05,490 --> 00:09:08,610 and I pass the mock callback into the function. 194 00:09:08,610 --> 00:09:12,330 This is the function I'm saying that it should invoke 195 00:09:12,330 --> 00:09:14,940 if the minimum value or the maximum value changes. 196 00:09:14,940 --> 00:09:18,750 And I can then verify that my mock function was invoked. 197 00:09:18,750 --> 00:09:19,900 We know how to do that. 198 00:09:21,030 --> 00:09:25,470 Right. I've got two tests in my product list, test TSX, 199 00:09:25,470 --> 00:09:29,460 one that will check if the minimum prices change 200 00:09:29,460 --> 00:09:33,000 does it gimme back a callback, and one for the maximum. 201 00:09:33,000 --> 00:09:34,710 Let's have a look at this. 202 00:09:34,710 --> 00:09:39,710 So first of all, I've registered a dummy callback function. 203 00:09:39,990 --> 00:09:43,290 That will be passed into my product list component. 204 00:09:43,290 --> 00:09:45,600 This is what's gonna be called back. 205 00:09:45,600 --> 00:09:50,340 So my product list, if the effect hook triggers, 206 00:09:50,340 --> 00:09:52,110 because the minimum value has changed, 207 00:09:52,110 --> 00:09:53,838 or the maximum value has changed, 208 00:09:53,838 --> 00:09:57,510 this, here, is the function that it's gonna call back. 209 00:09:57,510 --> 00:10:02,510 Okay. So it'll call back into this mock object here, right? 210 00:10:02,970 --> 00:10:04,350 So that's set things up. 211 00:10:04,350 --> 00:10:08,190 Let's emulate the user change in the minimum price. 212 00:10:08,190 --> 00:10:12,240 Okay. So I've emulated the user typing in a minimum price. 213 00:10:12,240 --> 00:10:15,750 The minimum text box, I set the value to a hundred. 214 00:10:15,750 --> 00:10:19,800 Okay. If the minimum value changes, remember the code. 215 00:10:19,800 --> 00:10:21,330 If the minimum value changes, 216 00:10:21,330 --> 00:10:23,970 my effect my effect hook should say, 217 00:10:23,970 --> 00:10:26,880 oh, the minimum value is changed. 218 00:10:26,880 --> 00:10:28,863 It should call the callback 219 00:10:28,863 --> 00:10:32,642 with the range changed to the minimum value 220 00:10:32,642 --> 00:10:34,533 and the maximum value. 221 00:10:35,400 --> 00:10:36,233 Okay. 222 00:10:36,233 --> 00:10:40,140 So let's verify that our range callback function was called. 223 00:10:40,140 --> 00:10:41,490 The range has been changed, 224 00:10:41,490 --> 00:10:43,500 the minimum value and the maximum value. 225 00:10:43,500 --> 00:10:47,490 Remember if the maximum value text box is empty 226 00:10:47,490 --> 00:10:50,280 then that we assume a default value of a million. 227 00:10:50,280 --> 00:10:53,940 Okay. So we can verify the effect has been invoked. 228 00:10:53,940 --> 00:10:57,660 I interacted with the user interface, or simulated it. 229 00:10:57,660 --> 00:10:59,940 My effect took should have realized 230 00:10:59,940 --> 00:11:01,890 that the minimum value has changed. 231 00:11:01,890 --> 00:11:03,570 It should call the callback, 232 00:11:03,570 --> 00:11:06,330 and it should have passed this value in like so. 233 00:11:06,330 --> 00:11:07,620 So I verified 234 00:11:07,620 --> 00:11:10,680 that the components' effect hook has been invoked, 235 00:11:10,680 --> 00:11:13,251 has invoked the callback function correctly. 236 00:11:13,251 --> 00:11:16,230 The second test is basically the same. 237 00:11:16,230 --> 00:11:18,960 Okay. I have a callback function here. 238 00:11:18,960 --> 00:11:23,010 I register, I render my product list component saying, 239 00:11:23,010 --> 00:11:24,093 call it back. 240 00:11:24,930 --> 00:11:27,180 I change the value of max. 241 00:11:27,180 --> 00:11:30,210 According to my effect hook, my effect, 242 00:11:30,210 --> 00:11:34,680 my effect hook says if the max value changes, call back 243 00:11:34,680 --> 00:11:37,290 with this value with that string. 244 00:11:37,290 --> 00:11:39,720 Okay. So it should say the range has changed, 245 00:11:39,720 --> 00:11:42,720 the minimum is zero, and the maximum is whatever value I've 246 00:11:42,720 --> 00:11:45,236 simulated the user input in. 247 00:11:45,236 --> 00:11:47,220 Okay. So that's it. 248 00:11:47,220 --> 00:11:48,930 We just need to run the tests 249 00:11:48,930 --> 00:11:51,690 and cross our fingers, and it works fine. 250 00:11:51,690 --> 00:11:53,823 So just to summarize what happened. 251 00:11:54,930 --> 00:11:58,290 Effect hooks are a mechanism widely used 252 00:11:58,290 --> 00:12:01,260 in React to do some additional work 253 00:12:01,260 --> 00:12:05,340 after your component has been rendered in Enzyme. 254 00:12:05,340 --> 00:12:08,790 We don't have any mechanism to this internal mechanism. 255 00:12:08,790 --> 00:12:11,396 We don't have any access to it, but we can, 256 00:12:11,396 --> 00:12:15,090 we can intercept that callback function. 257 00:12:15,090 --> 00:12:17,670 We can pass it, a dummy callback, 258 00:12:17,670 --> 00:12:21,120 and verify that it's been invoked with a correct parameter. 259 00:12:21,120 --> 00:12:22,110 And that's what we've done. 260 00:12:22,110 --> 00:12:22,943 And it worked.