1 00:00:02,300 --> 00:00:08,300 So let's continue working on this and let's change this to a let's say text change handler function 2 00:00:09,020 --> 00:00:10,390 which we now assigned to 3 00:00:10,400 --> 00:00:16,420 onChange text here on the title but which we also can add to our imageUrl. 4 00:00:16,430 --> 00:00:22,640 So here for onChange text, I also set this to text change handler and now for this to work, we need to 5 00:00:22,640 --> 00:00:28,030 make sure that this function gets information about which input it was triggered for, 6 00:00:28,070 --> 00:00:32,390 so whether you just typed in the title or in the imageUrl input. 7 00:00:32,570 --> 00:00:36,580 So besides getting the text, I also expect to get a different argument, 8 00:00:36,710 --> 00:00:42,290 I expect to get my input identifier or anything like that, you can name it whatever you want 9 00:00:42,290 --> 00:00:47,420 so that this function can be reused for multiple text inputs and we still get information about which 10 00:00:47,420 --> 00:00:48,560 input triggered this 11 00:00:48,680 --> 00:00:54,080 so that we can forward this to our reducer where we will later need this information to update our state 12 00:00:54,080 --> 00:00:55,370 correctly. 13 00:00:55,610 --> 00:01:01,520 Now to get this input identifier functionality, we need to go to the places where we use text change 14 00:01:01,520 --> 00:01:09,140 handler and there, we can for example use bind or use a wrapping anonymous arrow function instead to 15 00:01:09,140 --> 00:01:14,570 bind this where I don't care about but more importantly, to configure the arguments this function will 16 00:01:14,570 --> 00:01:19,700 get and there it's one special argument which I want to pass and that's the input identifier. 17 00:01:19,990 --> 00:01:24,650 And for this function here, for this function call on this text input, 18 00:01:24,650 --> 00:01:33,870 this of course would be title. For this input down there, we would have bound this imageUrl 19 00:01:34,060 --> 00:01:40,450 and again this should be an identifier which you also have in your state up there, in your form state 20 00:01:40,570 --> 00:01:49,110 which you pass to the reducer. With that added, we'll make sure that text change handler is executed and 21 00:01:49,110 --> 00:01:51,710 gets this input identifier argument. 22 00:01:51,990 --> 00:01:56,430 The text argument will also be received because that's the default argument which React Native would 23 00:01:56,430 --> 00:02:01,740 pass us anyways and this will then automatically be received as a last argument in that function. 24 00:02:01,800 --> 00:02:05,000 So we don't have to and we actually can't bind this here, 25 00:02:05,010 --> 00:02:07,410 it will be forwarded automatically. 26 00:02:07,680 --> 00:02:13,260 Now we have a reusable text change handler function here and we can assign this to the other inputs as well, 27 00:02:13,440 --> 00:02:21,030 like here to the imageUrl, like down here for the price, we can bind text change handler, bind 28 00:02:21,060 --> 00:02:27,390 this and then price is our identifier here and of course also for the description, there we 29 00:02:27,720 --> 00:02:35,540 paste this in and then bind to this and the identifier is description. 30 00:02:35,780 --> 00:02:40,910 Now this same handler can be used for all inputs but right now of course, it does one thing, 31 00:02:40,910 --> 00:02:44,240 it validates each input for its length. 32 00:02:44,240 --> 00:02:46,990 Now that might make sense and it does here, 33 00:02:47,030 --> 00:02:52,070 no input should be empty but you might want some other validation as well, 34 00:02:52,070 --> 00:02:58,130 for example my price here should be a number greater than zero 35 00:02:58,160 --> 00:03:05,360 let's say, so that zero is not allowed as an input. That on the other hand is not some criteria that matters 36 00:03:05,360 --> 00:03:10,670 to me on other inputs. We'll find an elegant solution for this later, 37 00:03:10,670 --> 00:03:16,700 for now let's stick with this smallest common denominator validation which we can apply to all inputs 38 00:03:16,700 --> 00:03:18,690 to make sure they're at least not empty 39 00:03:19,120 --> 00:03:23,040 and let's focus on the reducer function and how our form state should change 40 00:03:23,060 --> 00:03:26,990 when this form input update action with all that data is dispatched 41 00:03:26,990 --> 00:03:28,720 because right now nothing will happen. 42 00:03:28,760 --> 00:03:33,920 We have our initial state on the reducer there and that will be passed or stored in the form state but 43 00:03:33,920 --> 00:03:36,050 this state will never change. 44 00:03:36,080 --> 00:03:38,770 Well that's why we dispatch an action, right? 45 00:03:38,820 --> 00:03:40,550 That's why we do this here, 46 00:03:40,560 --> 00:03:46,190 this is why form input update is dispatched and that is why we want to write some code here in the 47 00:03:46,200 --> 00:03:49,190 reducer when this action reaches us here. 48 00:03:49,500 --> 00:03:55,650 Now in there, if this action reaches us, in the end the goal is to make sure that we update this state 49 00:03:55,650 --> 00:03:56,220 snapshot, 50 00:03:56,220 --> 00:03:58,340 our current state snapshot appropriately. 51 00:03:58,650 --> 00:04:04,470 This means that for example, we'll need some updated values and for this, I create a new object because my 52 00:04:04,470 --> 00:04:05,910 input values here, 53 00:04:06,030 --> 00:04:11,850 that's an object and I will create a new one to replace it and I will first of all copy the existing 54 00:04:11,850 --> 00:04:14,340 state input values. 55 00:04:14,400 --> 00:04:19,650 Keep in mind that the state here is passed in automatically, that's our current state snapshot before 56 00:04:19,650 --> 00:04:25,500 we update it and therefore initially, that's this state snapshot here for example and this will have an input 57 00:04:25,500 --> 00:04:27,610 values key which in turn holds an object 58 00:04:27,720 --> 00:04:29,420 and that's just what I'm copying here, 59 00:04:29,460 --> 00:04:35,910 I'm copying all the key-value pairs of that input values snapshot and then I want to replace the key 60 00:04:35,910 --> 00:04:40,230 value pair for the input for which this action was dispatched, 61 00:04:40,230 --> 00:04:46,740 the good thing is that we attach the input identifier to the action. So we can go to the reducer and 62 00:04:46,740 --> 00:04:52,360 dynamically override a key here in the copied input values, 63 00:04:52,380 --> 00:04:57,900 the key is action.input of course, that's our input identifier which we attached to the action and 64 00:04:57,900 --> 00:05:00,420 the value should be action.value, 65 00:05:00,420 --> 00:05:06,840 that's all we need to do. So we dynamically store the value that was dispatched with the also dynamically 66 00:05:06,840 --> 00:05:12,060 assigned input and update our copied input values. 67 00:05:12,060 --> 00:05:17,360 Now we can return a new state here because that's the goal of your own reducer, 68 00:05:17,360 --> 00:05:21,360 like for the Redux reducer, in the end it has to return a new state snapshot 69 00:05:21,840 --> 00:05:28,800 and there I want to copy the existing state but override the input values with the updated values which 70 00:05:28,800 --> 00:05:36,230 copies my old values so that no data is lost and then replaces one of the key-value pairs in there. Now obviously, 71 00:05:36,260 --> 00:05:39,820 it's not all to just replace the values or update the values, 72 00:05:39,890 --> 00:05:42,810 I also want to update my validities. 73 00:05:42,920 --> 00:05:48,700 So here are my updated validities and just as with the values, I start by copying my input 74 00:05:48,710 --> 00:05:53,240 validities key because the input validities is a key here 75 00:05:53,340 --> 00:05:54,050 as you can see 76 00:05:57,300 --> 00:06:05,190 and then I want to replace one validity for the input which we get on the action, so title, imageUrl 77 00:06:05,220 --> 00:06:10,320 or whatever it is and replace this with action is valid because we get the information whether that 78 00:06:10,320 --> 00:06:13,790 is valid or not as part of the action that is dispatched, right? 79 00:06:13,800 --> 00:06:17,400 We're forwarding this here based on this basic validation we have here. 80 00:06:19,810 --> 00:06:24,160 Now with that, we just need to update this here, 81 00:06:24,340 --> 00:06:30,220 so our input validities here are equal to the updated validities and now we just have to manage the 82 00:06:30,220 --> 00:06:33,430 overall form validity. For that, 83 00:06:34,640 --> 00:06:41,270 I add a variable, a helper variable, form is valid which initially is true and then I loop through all 84 00:06:41,270 --> 00:06:43,160 my updated validities 85 00:06:43,160 --> 00:06:45,050 which are my old copied validities 86 00:06:45,080 --> 00:06:49,520 and then the one updated validity for the input we just typed in. 87 00:06:49,580 --> 00:06:57,020 So here, we have a for/in loop where we go through all the keys in updated validities and the goal is 88 00:06:57,020 --> 00:07:03,170 simple, I check every form input validity and if all form input validities are valid, 89 00:07:03,170 --> 00:07:06,170 if they are all true, then the overall form is valid. 90 00:07:06,230 --> 00:07:08,980 If at least one of them is false, the overall form is false, 91 00:07:09,000 --> 00:07:17,090 the overall form is not valid. So therefore here form is valid is equal to the latest form is valid state 92 00:07:17,120 --> 00:07:24,320 we have and then the updated validities validity for the input w're currently looking at, so for this key 93 00:07:24,330 --> 00:07:26,320 and we're going through all the inputs here. 94 00:07:26,480 --> 00:07:31,530 The way this boolean operator works is such this false overrides true, 95 00:07:31,640 --> 00:07:37,730 so if any input is false, form is valid will be set to false and can't be set to true thereafter. 96 00:07:37,730 --> 00:07:43,010 So if at least one input is invalid, the overall form will be invalid and therefore now I don't need 97 00:07:43,010 --> 00:07:48,200 to copy my state anymore here because I will replace the entire state snapshot and set form 98 00:07:48,200 --> 00:07:51,460 is valid to my derived form is valid here 99 00:07:52,940 --> 00:08:02,910 and of course to avoid confusion, we could also name this updated form is valid here and here and here 100 00:08:03,540 --> 00:08:04,270 and here. 101 00:08:06,030 --> 00:08:09,900 Now just one additional thing, if we don't make it into this if block, 102 00:08:09,930 --> 00:08:16,560 so if some other action was dispatched or anything else, then I will just return the unchanged state 103 00:08:16,560 --> 00:08:18,870 here. With that, 104 00:08:18,870 --> 00:08:26,590 we added a reducer logic that is able to handle any input or any typing into any of our text inputs, 105 00:08:26,610 --> 00:08:31,560 now we just need to use the form state which will change with every keystroke which is just what happened 106 00:08:31,560 --> 00:08:38,010 before but now all centralized and merged into one managed state which I think is way cleaner than having 107 00:08:38,190 --> 00:08:45,600 tons of different states for validities and values. And by the way, managing all these states manually and 108 00:08:45,600 --> 00:08:53,330 separately would have become a big problem when you then want to validate the overall form validity. 109 00:08:53,340 --> 00:08:59,250 So now we can use the form state which will change with every keystroke and we use it for example here 110 00:08:59,790 --> 00:09:07,610 on the values. We pass back in the value for this text input by accessing form state input values.title. 111 00:09:07,620 --> 00:09:15,160 Now obviously, we do the same here for the imageUrl, we feed this back in, 112 00:09:15,160 --> 00:09:19,710 so just what we did before and now with our form state managed with the help of the reducer, 113 00:09:19,720 --> 00:09:26,040 same for the price of course and also the same for the description, like that. 114 00:09:29,530 --> 00:09:35,010 Now besides changing it here, we also have to change it in some other places, 115 00:09:35,140 --> 00:09:39,730 for example here in the submit handler of course. There, title is valid, 116 00:09:39,730 --> 00:09:50,540 this no longer exists but we can check form state input validities title, that is true or false and 117 00:09:50,540 --> 00:09:52,250 if it's false, it means it's not valid, 118 00:09:52,250 --> 00:09:54,400 so this check should be fine. 119 00:09:54,530 --> 00:09:59,960 Of course however we care about the validity of all inputs, 120 00:09:59,960 --> 00:10:05,270 so instead of just checking them all manually here by concatenating them into a long if statement, we can 121 00:10:05,270 --> 00:10:10,880 just check if form state form is valid is false because that means some input is false and therefore 122 00:10:10,880 --> 00:10:11,750 we show this error, 123 00:10:11,750 --> 00:10:18,300 that's the shorter check and this is of course also when we want to avoid that the form gets submitted. 124 00:10:18,300 --> 00:10:23,450 If the form gets submitted however, title description and imageUrl, that no longer exists, 125 00:10:23,550 --> 00:10:29,380 instead that's now form state inputValues.title and so on, 126 00:10:29,400 --> 00:10:30,950 so we do the same here 127 00:10:32,290 --> 00:10:40,790 for the description and for the imageUrl. We derive our values from the form state, same of course 128 00:10:40,790 --> 00:10:50,250 here for creating. We get the title and the description and the imageUrl and also of course the price 129 00:10:50,250 --> 00:10:55,200 which I still convert to a number with the plus here, we get all of that out of our form state of 130 00:10:55,200 --> 00:11:02,130 the input values. Therefore of course our dependency here is not title, description, imageUrl and so on, 131 00:11:02,130 --> 00:11:08,490 instead it's just form state. If the form states changes, which it will on every keystroke, then this 132 00:11:08,490 --> 00:11:13,170 function should be rebuilt and it needs to be rebuilt because the information that's used by the function 133 00:11:13,200 --> 00:11:14,790 changes with every keystroke, 134 00:11:14,790 --> 00:11:16,980 the validity can change with every keystroke, 135 00:11:17,070 --> 00:11:23,750 the values you want to submit can change with every keystroke. 136 00:11:23,880 --> 00:11:29,820 We also can of course now use this to show our error message. Instead of checking title is valid which 137 00:11:29,820 --> 00:11:31,330 doesn't exist anymore, 138 00:11:31,380 --> 00:11:41,850 we check formState.inputValidities.title, if that is false, then I want to show this text. 139 00:11:41,960 --> 00:11:42,680 So now with that, 140 00:11:42,680 --> 00:11:47,440 if we save all of that, we should be able to check this. If we go to our page here, 141 00:11:47,450 --> 00:11:49,320 we see this error initially. 142 00:11:49,340 --> 00:11:51,650 If I start typing, it disappears, if I 143 00:11:51,690 --> 00:11:55,640 try to submit this, it fails because I have three empty inputs. 144 00:11:55,640 --> 00:11:58,800 If I do enter something valid there on the other hand, 145 00:11:58,850 --> 00:12:02,100 this works. If I try editing, 146 00:12:02,270 --> 00:12:05,100 let's try this on Android maybe to mix things up. 147 00:12:05,420 --> 00:12:11,140 So if I try editing the red shirt here, I can submit this just fine, 148 00:12:11,150 --> 00:12:13,290 now let's also try submitting this if 149 00:12:13,320 --> 00:12:18,080 this is empty, then I get the alert. 150 00:12:18,080 --> 00:12:20,620 So this works in the way that it should work, 151 00:12:24,840 --> 00:12:31,700 now with this more elegant form management using use reducer and of course you can not just use use reducer 152 00:12:31,700 --> 00:12:33,020 when working with forms, 153 00:12:33,080 --> 00:12:38,660 this is just a particularly good example for when it makes sense to merge multiple states together and 154 00:12:38,660 --> 00:12:42,250 therefore have highly reusable and efficient code. 155 00:12:42,270 --> 00:12:48,290 Now I'm still not done though because all this code repetition with the inputs here which are always 156 00:12:48,320 --> 00:12:54,880 structured in the same way and the missing customization possibilities regarding the validation, 157 00:12:55,040 --> 00:12:56,930 these are the things I want to tackle next.