1 00:00:02,290 --> 00:00:08,140 Our approach here of course works. We're storing the inputs in some state, we're storing the validity 2 00:00:08,140 --> 00:00:16,090 in some state and we could do this validity management for all our inputs here and simply have our different 3 00:00:16,120 --> 00:00:21,370 change handler functions here for our different inputs, that would work. 4 00:00:21,370 --> 00:00:26,560 One important note by the way before we move on, since I check the title validity here in the submit handler, 5 00:00:26,770 --> 00:00:29,950 of course we should also add it there as a dependency, 6 00:00:29,950 --> 00:00:35,820 so title is valid must be added there as a dependency in the use callback dependency array, 7 00:00:35,830 --> 00:00:36,980 that's important, 8 00:00:37,030 --> 00:00:40,570 otherwise this function will not be rebuilt when that validity changes 9 00:00:40,660 --> 00:00:47,970 which means we won't be able to submit it thereafter. The problem with our current approach is that 10 00:00:47,970 --> 00:00:55,410 we manage different states to store the input for the different inputs and then we also have different 11 00:00:55,410 --> 00:01:00,910 validity states, at least potentially if we start managing our validity, like this 12 00:01:00,990 --> 00:01:07,400 and for very large forms, of course this means a lot of copy and pasting, a lot of state management. 13 00:01:07,410 --> 00:01:15,300 Now if you have that many states that are kind of connected, you also can do this in a more elegant way, 14 00:01:15,330 --> 00:01:18,500 instead of having your separate states for each input, 15 00:01:18,540 --> 00:01:25,720 you can have one big state which merges all input values and which merges all validities and then use 16 00:01:25,740 --> 00:01:33,720 a concept called a reducer, not a Redux reducer but one supported by React out the box to manage that 17 00:01:33,720 --> 00:01:34,710 state. 18 00:01:34,710 --> 00:01:40,210 You do this with the use reducer hook which again has nothing to do with Redux, 19 00:01:40,440 --> 00:01:47,550 the concept of a reducer is not Redux exclusive, a reducer in the end is just a function that takes input 20 00:01:47,580 --> 00:01:52,800 and spits out some output and therefore React also supports this and you'll see how you can use this 21 00:01:52,920 --> 00:01:54,190 in this lecture now. 22 00:01:54,900 --> 00:01:57,510 So what's the idea of a reducer? Now 23 00:01:57,510 --> 00:02:03,030 first it's important to understand that use reducer is a hook that helps you have state management. Typically 24 00:02:03,090 --> 00:02:09,420 you use it if you have connected states or more complex state and you don't want have a bunch of individual 25 00:02:09,600 --> 00:02:16,340 use state calls and a bunch of individual states which you manage. You then can use use reducer 26 00:02:16,350 --> 00:02:17,510 and here's how it works. 27 00:02:19,060 --> 00:02:25,530 You start by creating a reducer, let's say a form reducer here, you can name it whatever you want 28 00:02:25,570 --> 00:02:29,020 and please note I create it outside of my form component, 29 00:02:29,020 --> 00:02:33,940 you could do it in there but if you don't depend on props, you can do it outside of there so that this 30 00:02:33,940 --> 00:02:39,250 won't rebuild with every re-render cycle and you don't even have to use use callback which of course 31 00:02:39,280 --> 00:02:44,110 also costs some performance if you use it. So use it outside of there, build it outside of there 32 00:02:44,110 --> 00:02:49,690 to avoid unnecessary recreations of that function and now the reducer, just like a Redux reducer 33 00:02:49,690 --> 00:02:57,100 gets the current state and an action but again it's not related to Redux, it's not used by Redux, 34 00:02:57,360 --> 00:03:02,240 reducer functions just always kind of work like this. Now in there, 35 00:03:02,310 --> 00:03:07,260 again just like in a Redux reducer because again, they work like this, 36 00:03:07,260 --> 00:03:11,520 you can check different action types and here I want to check one type, this as well 37 00:03:11,520 --> 00:03:12,680 just use an if statement, 38 00:03:12,690 --> 00:03:15,440 you could use a switch case statement as well 39 00:03:15,750 --> 00:03:19,260 and that I check action.type here is totally up to me, 40 00:03:19,290 --> 00:03:24,030 you can name this whatever you want because you will be the one dispatching the action later and here 41 00:03:24,030 --> 00:03:29,800 I check for the update action which also is an identifier I chose and which just like in Redux, 42 00:03:29,820 --> 00:03:39,050 you could also store this identifier in a standalone constant here, so you could have your reducer update 43 00:03:39,620 --> 00:03:45,850 action here for example, your reducer update identifier like this and use this instead here 44 00:03:45,920 --> 00:03:48,260 if you wanted to and you can name this whatever you want. 45 00:03:48,380 --> 00:03:57,180 So now I'm checking for this action and if this action occurs, I want to store an input value and validate it 46 00:03:57,340 --> 00:04:00,850 but to understand this, we need to understand how we use the form reducer. 47 00:04:00,920 --> 00:04:05,510 So let's leave it like this for the moment and go down to the component itself, 48 00:04:05,600 --> 00:04:08,950 there we start setting up our form state down here, 49 00:04:08,960 --> 00:04:15,200 so here I want to call user reducer and now use reducer take such a reducer function hence I will 50 00:04:15,200 --> 00:04:19,540 pass in my form reducer which I set up here and which is still unfinished. 51 00:04:19,940 --> 00:04:24,990 Use reducer also takes some optional second argument which is the initial state you want to pass 52 00:04:24,990 --> 00:04:30,860 in and that can be anything but here I'll pass in a Javascript object and the initial state I want to 53 00:04:30,860 --> 00:04:38,630 use here is in the end an object which has input values, which then is yet another nested object which I'll 54 00:04:38,630 --> 00:04:39,990 soon populate, 55 00:04:40,220 --> 00:04:46,670 input validities which also is a nested object and maybe an overall form validity, 56 00:04:46,670 --> 00:04:49,610 I'll name it form is valid which initially is false 57 00:04:49,620 --> 00:04:55,700 let's say. So this is now my initial state I pass in here and that's the state which I later want to 58 00:04:55,700 --> 00:05:03,260 change from inside the form reducer. Now on the input values, we can for example add our title and that 59 00:05:03,260 --> 00:05:06,070 is up to you how you name it, which is an empty string initially 60 00:05:06,070 --> 00:05:11,150 let's say, these will be the initial values I want to set on my inputs this will in the end replace 61 00:05:11,150 --> 00:05:15,980 my state management down there, where I manually store my inputs in different states. 62 00:05:15,980 --> 00:05:20,220 Now I will merged this all into one object managed through that reducer. 63 00:05:20,480 --> 00:05:25,610 So I have my title here and actually that's not always empty of course but actually it's only empty 64 00:05:25,610 --> 00:05:27,410 if we have no edited product, 65 00:05:27,410 --> 00:05:31,140 so I will copy this check from there and use this in here. 66 00:05:31,370 --> 00:05:34,590 Now the same of course for the imageUrl, there 67 00:05:35,410 --> 00:05:40,150 I initialize this with editedProduct.imageUrl if it's available and otherwise I 68 00:05:40,150 --> 00:05:40,930 use an empty string, 69 00:05:40,930 --> 00:05:43,540 basically what I did down there as well. 70 00:05:44,110 --> 00:05:48,030 And of course I do the same for the description, here 71 00:05:48,070 --> 00:05:52,990 I want to check if edited product is set and I use this description or set it to an empty string 72 00:05:53,080 --> 00:05:59,410 if it's not available. Now last but not least, we have the price and there I always have an empty string 73 00:05:59,410 --> 00:06:02,450 because we either don't need it in the case of an edited product, 74 00:06:02,470 --> 00:06:05,830 then I don't care about its value or we do need it, 75 00:06:05,860 --> 00:06:08,140 well then I want to initialize it with an empty value 76 00:06:08,140 --> 00:06:15,020 anyways. Now of course each input also has a validity, so we can add a title here and again check whether 77 00:06:15,020 --> 00:06:16,790 editedProduct is set, 78 00:06:16,850 --> 00:06:19,010 if it is set, then I know I'm editing, 79 00:06:19,040 --> 00:06:21,320 so we will have prepopulated the title, 80 00:06:21,320 --> 00:06:22,700 so initially it will be valid, 81 00:06:22,700 --> 00:06:24,950 so in this case my initial value would be true, 82 00:06:24,950 --> 00:06:32,250 otherwise it will be false and now this is also something we can repeat for the imageUrl. If we have 83 00:06:32,250 --> 00:06:33,080 an edited product, 84 00:06:33,080 --> 00:06:36,650 we know it was prepopulated, therefore it will be valid initially, 85 00:06:36,650 --> 00:06:39,550 so we set this to true otherwise I set it to false. 86 00:06:39,740 --> 00:06:44,420 For my description here, it's the same - true or false 87 00:06:44,540 --> 00:06:46,760 and for the price, it's kind of equal, 88 00:06:46,760 --> 00:06:49,090 of course we don't prepopulate the price 89 00:06:49,100 --> 00:06:55,200 if we're editing but if we are editing I don't care about the price anyways because it will not be changeable. 90 00:06:55,310 --> 00:07:00,890 Therefore I know if I am editing, I should treat this as valid because it can't be changed anyways and 91 00:07:00,890 --> 00:07:02,420 therefore I don't care about this input 92 00:07:02,440 --> 00:07:09,680 but I don't want to block form submission because of setting this to false when we can't edit it anyways. 93 00:07:09,980 --> 00:07:13,110 So I will set it to true if this is not planned to be edited, 94 00:07:13,190 --> 00:07:18,770 if we're not editing a product but we're adding one, the price will be editable and therefore we will start 95 00:07:18,770 --> 00:07:24,230 in a false state because the price input will be empty initially, that's what we're setting up here. And 96 00:07:24,320 --> 00:07:26,150 now the overall form validity, 97 00:07:26,150 --> 00:07:31,130 well there again I can check if we have an edited product, which means we are editing, then the form is 98 00:07:31,130 --> 00:07:33,590 true, the form is valid initially, 99 00:07:33,590 --> 00:07:39,240 otherwise it's false initially if we're adding a new product. Now this is my initial state here, 100 00:07:39,260 --> 00:07:45,050 now this reducer function should be able to change that state when actions are dispatched and an action 101 00:07:45,050 --> 00:07:48,660 should be dispatched whatever we type into one of our text inputs, 102 00:07:48,730 --> 00:07:58,190 that will be the trigger. So therefore, we can now get rid of all these state assignments here and hence 103 00:07:58,220 --> 00:08:05,780 we can also get rid of the entire use state import even and make sure we dispatch the reducer 104 00:08:05,790 --> 00:08:09,610 update action for every keystroke we do in an input. 105 00:08:09,710 --> 00:08:18,670 So here in the title change handler, I in the end will remove this code, I'll leave the if check for now but 106 00:08:18,740 --> 00:08:22,770 I'll not have any code in there for the moment, instead down there, 107 00:08:22,790 --> 00:08:28,960 I want to dispatch reducer update and now this is done with the result of the use reducer call because 108 00:08:28,960 --> 00:08:35,000 use reducer of course return something, just like use state did. It also returns an array with exactly 109 00:08:35,000 --> 00:08:40,710 two elements and therefore we can destructure it with this array destructuring syntax which we also 110 00:08:40,730 --> 00:08:47,450 used on use state and there I get my form state as a first value and a dispatch function as a second 111 00:08:47,450 --> 00:08:48,250 value. 112 00:08:48,290 --> 00:08:55,280 This is always what use reducer will return you, a state snapshot which updates whenever you change it 113 00:08:55,280 --> 00:08:55,770 of course, 114 00:08:55,790 --> 00:09:01,490 so whenever you change it, this component will rerender and give you a new state snapshot and a function, 115 00:09:01,550 --> 00:09:07,160 dispatch in the end is a function that allows you to dispatch actions against this reducer. 116 00:09:07,250 --> 00:09:11,760 Of course, you can name these two elements however you want but I think this is a sensible naming, 117 00:09:11,780 --> 00:09:13,270 this is our state snapshot, 118 00:09:13,280 --> 00:09:20,100 this is a function. Now dispatch by the way is a name I already used here from Redux, 119 00:09:20,100 --> 00:09:24,460 so here I will name this dispatch form state to avoid a name clash, 120 00:09:24,480 --> 00:09:25,980 you can name it however you want. 121 00:09:26,760 --> 00:09:33,350 So dispatch form state can now be used here in my title change handler, 122 00:09:33,410 --> 00:09:39,170 I just call it and I need to pass an object there which describes my action and this object will have 123 00:09:39,170 --> 00:09:40,820 a type property, 124 00:09:40,820 --> 00:09:46,130 you don't have to have a type property, you could name this ID or identifier or whatever you want but 125 00:09:46,130 --> 00:09:52,010 I use type here because I actually do check for the type property inside of my reducer function and 126 00:09:52,010 --> 00:09:59,260 this reducer function will be executed for every new action you dispatch. So if I go back down there, 127 00:09:59,500 --> 00:10:07,650 the type will be reducer update or maybe a better name actually would be form update I think, so that's 128 00:10:07,650 --> 00:10:10,830 also what I'll use up here of course and up here, 129 00:10:10,830 --> 00:10:18,750 so form update, maybe form input update, the name of course is up to you but it should be clear about 130 00:10:18,750 --> 00:10:19,790 what it does, 131 00:10:19,800 --> 00:10:22,110 so here, I'll also have form input update, 132 00:10:22,180 --> 00:10:23,280 yes that looks good. 133 00:10:23,280 --> 00:10:24,510 So form input update, 134 00:10:24,510 --> 00:10:26,120 that's what I dispatched down there, 135 00:10:26,130 --> 00:10:27,600 we need to change it here as well 136 00:10:27,600 --> 00:10:33,100 and of course you can also pass any other data you might want to use inside of your reducer 137 00:10:33,210 --> 00:10:38,250 and I do have some other data which I want to use. That would be the value and I'll just name this value 138 00:10:38,250 --> 00:10:39,270 here, this property, 139 00:10:39,300 --> 00:10:40,730 you can name it however you want, 140 00:10:40,740 --> 00:10:42,390 that's the text which was entered, 141 00:10:42,420 --> 00:10:48,490 so I just forward that to the reducer so that we can store it in our state there and the validity of 142 00:10:48,490 --> 00:10:49,400 this input. 143 00:10:49,470 --> 00:11:02,110 So therefore here, I will actually add an is valid prop which initially let's say is false and now I will 144 00:11:02,110 --> 00:11:07,480 remove this else case and check if we're greater than zero here which would mean that it should be 145 00:11:07,480 --> 00:11:12,850 true because then I set is valid equal to true, otherwise it will stay false and 146 00:11:12,850 --> 00:11:19,050 with that, we can also add is valid as a key to the action and forward the value stored inside of our 147 00:11:19,060 --> 00:11:20,230 is valid variable 148 00:11:20,350 --> 00:11:26,320 and this will be false initially but if our input length for the title is greater than zero, then it 149 00:11:26,320 --> 00:11:35,230 will actually be true and now we of course also need to let our reducer know which input triggered this. 150 00:11:35,330 --> 00:11:43,730 So I'll add an input ID field here or just input, whatever you like and use title here 151 00:11:43,730 --> 00:11:49,670 and this key here should be a key which you also have inside of your state, like here in input values 152 00:11:49,790 --> 00:11:54,800 and input validities because this will allow you to write some reducer code which we'll do soon 153 00:11:54,890 --> 00:12:01,920 that is highly reusable and highly flexible because now we can take the next step and make sure that 154 00:12:01,920 --> 00:12:09,210 we transform this to be a function that actually works for all inputs and that is really flexible regarding 155 00:12:09,210 --> 00:12:10,080 how we use it.