1 00:00:02,630 --> 00:00:05,410 Let's start with the favorites. 2 00:00:05,420 --> 00:00:13,270 I want to make sure that when I'm in a recipe, I can click that star and that adds this as a favorite 3 00:00:13,660 --> 00:00:18,490 and shows it here in the favorite screen where I currently see nothing because I removed these dummy favorites. 4 00:00:19,880 --> 00:00:20,200 For that 5 00:00:20,210 --> 00:00:25,830 I'll start in the store folder, in the actions folder and add a new folder which I'll also name meals.js, 6 00:00:25,840 --> 00:00:30,570 you can name it differently if that's confusing to you but yes, these two files meals.js here 7 00:00:30,560 --> 00:00:34,970 in actions and meals.js in reducers and in the actions meals.js 8 00:00:34,960 --> 00:00:41,900 file, I will set up some Redux actions which typically starts by setting up some unique identifiers 9 00:00:41,930 --> 00:00:48,760 which I store in constants and that will be toggle favorites. 10 00:00:49,070 --> 00:00:50,710 You can use whatever you want here, 11 00:00:50,780 --> 00:00:53,860 the value you store here typically is the same identifier, 12 00:00:54,350 --> 00:00:59,570 so this is the identifier value and that is simply stored in a constant so that we don't have to manually 13 00:00:59,570 --> 00:01:02,870 type this later but we can always import this constant and avoid 14 00:01:02,870 --> 00:01:03,690 typos. 15 00:01:03,860 --> 00:01:05,440 Again if it's brand new to you, 16 00:01:05,440 --> 00:01:09,730 definitely check out a dedicated React Redux resource first. 17 00:01:09,950 --> 00:01:12,680 Now I'll also use the action creator pattern here 18 00:01:12,680 --> 00:01:19,190 which means I have that identifier here but now I will also export a function that creates me an action 19 00:01:19,280 --> 00:01:24,050 because an action is not just an identifier often and in this case that's the case, 20 00:01:24,050 --> 00:01:29,630 it also needs some extra payload and therefore we actually have an action which is an object with identifier 21 00:01:29,780 --> 00:01:35,930 and payload and therefore here, I'll add a function that creates me such an action object and I'll name this 22 00:01:35,930 --> 00:01:37,430 toggle favorite like this, 23 00:01:37,490 --> 00:01:42,950 select the identifier but in camel case and this is a function that can receive some data because I will 24 00:01:42,950 --> 00:01:48,500 be the one calling it and that should return a Javascript object which describes this action, so which 25 00:01:48,500 --> 00:01:50,300 has let's say a type, 26 00:01:50,330 --> 00:01:55,010 that's typically how you call that identifier field but you're generally free to use whatever you want 27 00:01:55,010 --> 00:01:55,590 there 28 00:01:55,670 --> 00:01:57,490 and in my case, that will be toggle favorite, 29 00:01:57,500 --> 00:02:03,700 so I point at this identifier, I use this string as an identifier and then any extra data you want, 30 00:02:03,740 --> 00:02:09,500 for example here I'll need to add the meal ID of the meal which should be toggled and that means 31 00:02:09,500 --> 00:02:14,540 that this function also needs to get this ID an an input because otherwise I can't store it in the action 32 00:02:14,540 --> 00:02:16,700 which I created. 33 00:02:16,710 --> 00:02:21,120 So this is my action creator for the toggle favorite action, now in the reducer, 34 00:02:21,120 --> 00:02:27,810 I want to act when I get such a toggle favorite action and for this, I'll use a pattern which you probably 35 00:02:27,810 --> 00:02:28,370 have seen 36 00:02:28,380 --> 00:02:34,020 if you worked with Redux before, I'll use a switch statement here and switch on my action type because 37 00:02:34,020 --> 00:02:40,890 keep in mind that action will be an object with a type property which identifies the action that occurred. 38 00:02:40,890 --> 00:02:45,330 So I switch on that action type and then I handle different cases for the different actions I might 39 00:02:45,330 --> 00:02:46,650 have. 40 00:02:46,650 --> 00:02:53,040 So here I have the toggle favorite action and for this, you need to import toggle favorite from actions meals 41 00:02:53,390 --> 00:02:58,590 and that's why I'm storing this in the separate constant because now I don't have to manually type toggle 42 00:02:58,590 --> 00:03:00,820 favorites where I might have a typo in there, 43 00:03:00,840 --> 00:03:07,410 instead I just use that constant in which the string is stored. And now here, I run whichever logic I 44 00:03:07,410 --> 00:03:13,310 want to run to then work with that action and change my state such that the meal with the meal ID 45 00:03:13,350 --> 00:03:19,470 that's part of my action is added to favorite meals or removed from there if it already was part because 46 00:03:19,470 --> 00:03:20,790 it's a toggle action here, 47 00:03:20,820 --> 00:03:28,770 I want to add items that aren't favorites yet, I want to remove items that are. Side note, in the switch 48 00:03:28,770 --> 00:03:29,250 statement, 49 00:03:29,250 --> 00:03:33,150 I also will add a default case where I just return the unchanged state. 50 00:03:33,150 --> 00:03:36,900 We shouldn't really reach that but in case we do, well then that's what we do 51 00:03:37,380 --> 00:03:40,800 but back to the toggle favorite case. In there, 52 00:03:42,770 --> 00:03:48,740 I now want to in the end find out whether my meal with the ID that's part of the action because I'm 53 00:03:48,740 --> 00:03:50,450 adding the meal ID to the action, 54 00:03:50,450 --> 00:03:52,550 if that meal is already part of favorite meals, 55 00:03:52,550 --> 00:03:53,660 if yes I want to remove it, 56 00:03:53,690 --> 00:04:00,960 if it's not, I want to add it. So for this, I'll start by finding the index of the meal 57 00:04:00,960 --> 00:04:07,380 in the favorite meals array because if that is then -1, I know I didn't find an index so it wasn't 58 00:04:07,390 --> 00:04:07,820 part, 59 00:04:07,840 --> 00:04:13,540 if that's greater or equal than zero, I know that the item was part of that. So I'll have my existing 60 00:04:13,540 --> 00:04:21,960 index here and I get this by using state favorite meals and there I entered an equals sign and state 61 00:04:22,010 --> 00:04:27,510 is simply my current state snapshot which I get and there, we'll have a favorite meals property and I 62 00:04:27,510 --> 00:04:33,780 can use the find index method, a normal Javascript method which I can use on arrays to get the index 63 00:04:33,840 --> 00:04:39,810 of an item that matches a certain criteria which I set up here in a function I pass to find index, 64 00:04:40,230 --> 00:04:47,040 this function runs on every meal in the array and if it returns true, then it gives me the index of the 65 00:04:47,040 --> 00:04:48,610 element for which it ran through. 66 00:04:48,660 --> 00:04:56,900 So here I want to return true if meal.id is equal to action.mealId. That simply means that 67 00:04:56,930 --> 00:05:02,090 the meal I'm looking at in my favorite meals has the same idea as the meal for which this action occurs 68 00:05:02,090 --> 00:05:08,450 and that means if that is true for any item in favorite meals, that the meal we're trying to toggle is 69 00:05:08,540 --> 00:05:13,490 already part of the favorites, so we'll have to remove it because this will now return us the index of 70 00:05:13,490 --> 00:05:13,990 the item, 71 00:05:13,990 --> 00:05:20,090 therefore existing index will be greater than -1 and therefore, we can then use that index to 72 00:05:20,090 --> 00:05:21,120 remove it. 73 00:05:21,170 --> 00:05:23,660 If this returns true for no item, 74 00:05:23,720 --> 00:05:29,870 so if this in the end returns -1, I know that the item isn't part of favorite meals yet. So existing 75 00:05:29,870 --> 00:05:34,520 index holds very important information and hence I will use it here in an if statement and check if existing 76 00:05:34,520 --> 00:05:40,760 index is greater or equal than 0, which means we already have that meal as part of the favorite meals 77 00:05:41,390 --> 00:05:43,040 or not. 78 00:05:43,040 --> 00:05:48,290 Now in the if case, so the item already is part of the favorite meals, I want to remove it. 79 00:05:48,290 --> 00:05:53,210 So here, I will in the end return a new state because in your reducer, in the end, you have to return 80 00:05:53,210 --> 00:06:00,740 a new state which is a new object where I first of all copy the existing state with the spread operator 81 00:06:00,740 --> 00:06:01,110 here to 82 00:06:01,110 --> 00:06:05,810 pull out all the key-value pairs of the existing state, so that I don't lose any state and don't 83 00:06:05,870 --> 00:06:06,980 override any state 84 00:06:06,980 --> 00:06:12,200 I don't want to override and then I will only override the favorite meals, so I'll add this property 85 00:06:12,200 --> 00:06:17,870 again to override the existing favorite meals with my new favorite meals which should in the end be the 86 00:06:17,930 --> 00:06:21,520 old favorite meals without the item on this index. 87 00:06:24,250 --> 00:06:30,360 And now here to get my updated favorite meals, I'll create a new constant, updatedFavMeals, there I will 88 00:06:30,360 --> 00:06:39,470 first of all create a new array and populate it with my existing meals, so move my existing favorite meals 89 00:06:39,470 --> 00:06:46,240 like this and I do this to create a copy of that array so that I don't manipulate the original array 90 00:06:46,250 --> 00:06:53,000 if I now start working on that because now I want to take my updatedFavMeals, call splice here 91 00:06:53,660 --> 00:06:57,470 and then remove the item at the existing index and only that item. 92 00:06:57,470 --> 00:07:03,950 So this will in the end take this updatedFavMeals index, edit it and remove the item at this index 93 00:07:04,250 --> 00:07:06,200 and edit this array, 94 00:07:06,200 --> 00:07:12,110 that's why I copied it so that I don't edit the original array and now we can use this updatedFavMeals 95 00:07:12,110 --> 00:07:17,330 array here and store this back as favorite meals into our store because that will be the favorite 96 00:07:17,390 --> 00:07:19,880 meals array without the meal we just removed. 97 00:07:23,360 --> 00:07:29,680 In the else case which is of course relevant if we're not finding a product so we want to add it, here 98 00:07:29,690 --> 00:07:36,380 I also want to return a new state where I first of all copy the old state and then I will override 99 00:07:36,380 --> 00:07:42,230 favorite meals to basically be my old favorite meals 100 00:07:42,230 --> 00:07:48,380 and now I can call concat, a Javascript method built into Javascript which returns a new array 101 00:07:48,410 --> 00:07:55,520 which takes the old array and adds a new item and there, I want to add the meal for that ID here 102 00:07:55,700 --> 00:08:05,130 and of course I can find that meal on my state, there on meals, this is this property, state here always 103 00:08:05,130 --> 00:08:08,940 refers just to this state structure here by the way 104 00:08:08,940 --> 00:08:14,240 and now here, I can find the meal which I want to add 105 00:08:14,380 --> 00:08:18,210 and since this gets very long, I'll actually outsource this into a new line, 106 00:08:18,490 --> 00:08:27,770 so my meal which I want to add can be found with the find method which runs on all meals and there, if 107 00:08:27,800 --> 00:08:33,560 mealId is equal to action.mealId, then I have the meal I want to add and it's this meal which 108 00:08:33,560 --> 00:08:40,180 I concatenate to my favorite meals, so that I add this to that array. That should be logic that works 109 00:08:40,180 --> 00:08:45,690 and that manages our favorites. 110 00:08:45,700 --> 00:08:52,120 Now we need to make sure that we actually dispatch this action whenever we click that star icon in our 111 00:08:52,120 --> 00:08:52,540 header. 112 00:08:55,360 --> 00:08:56,570 To dispatch the action, 113 00:08:56,570 --> 00:09:00,550 let's go to the meal detail screen because that's where we have our star 114 00:09:00,550 --> 00:09:05,590 icon here and when I press this button, I in the end want dispatch an action. 115 00:09:05,710 --> 00:09:08,520 Good news is dispatching actions is very easy, 116 00:09:08,530 --> 00:09:09,800 we got use selector, 117 00:09:09,850 --> 00:09:16,190 we also got use dispatch which in the end gives us an easy way of firing a function. 118 00:09:16,200 --> 00:09:24,110 The bad news is that this of course can only be used in the component body here, in our functional component 119 00:09:24,260 --> 00:09:26,150 and not in the navigation options. 120 00:09:26,210 --> 00:09:32,690 So we'll again have to work with set params to communicate between navigation options and the component 121 00:09:32,720 --> 00:09:37,970 but that is something we can of course do. So here in meal detail screen, 122 00:09:38,040 --> 00:09:45,470 I'll simply start by calling use dispatch and what this does is it gives us a dispatch function, a function 123 00:09:45,470 --> 00:09:53,650 we can call to dispatch new actions and I'll store in a constant named dispatch. Next, I want to create 124 00:09:53,650 --> 00:10:01,210 a toggle favorite handler which is a function which in the end should dispatch this action. 125 00:10:01,210 --> 00:10:06,390 So here I want to call dispatch which I have available thanks to this hook 126 00:10:06,610 --> 00:10:10,600 and now to dispatch, I need to forward the action which I want to dispatch 127 00:10:10,600 --> 00:10:14,410 and for this, I'll use this action creator toggle favorite here. 128 00:10:14,620 --> 00:10:18,340 So we just have to import this, import 129 00:10:20,780 --> 00:10:27,410 from the store folder, there from actions and there from the meals.js file, from there 130 00:10:27,410 --> 00:10:35,740 I want to import toggle favorite, not the identifier in all caps but this action creator function. With 131 00:10:35,740 --> 00:10:40,940 that imported here, in dispatch we can call toggle favorite like this and now here we need to forward the 132 00:10:40,940 --> 00:10:45,440 ID and that of course is the mealId which we're already extracting up there 133 00:10:48,480 --> 00:10:53,310 or selectedMeal.Id would also work, whatever you want, 134 00:10:55,350 --> 00:10:58,910 I'll simply go for the mealId like this. 135 00:10:59,010 --> 00:11:07,110 Now we can reactivate use effect to communicate to our header, not with this line though but instead 136 00:11:07,110 --> 00:11:14,130 with props navigation set params and now here, I'll name this toggle fav, the name is up to you and 137 00:11:14,130 --> 00:11:16,890 point at my toggle favorite handler. 138 00:11:16,890 --> 00:11:22,980 Now toggle favorite handler should therefore be added as a dependency here and to avoid infinite loops, 139 00:11:23,580 --> 00:11:30,180 I'll again use use callback which I import from React to wrap this function here. 140 00:11:30,180 --> 00:11:37,060 So here use callback is wrapped around this function and we need to specify dependencies here 141 00:11:37,200 --> 00:11:40,020 and dependency number one is dispatch, 142 00:11:40,020 --> 00:11:44,640 React Redux will make sure that this never changes though, so that's a dependency which will never change, 143 00:11:45,210 --> 00:11:46,730 dependency two is mealId, 144 00:11:46,740 --> 00:11:49,270 that also shouldn't change whilst we're on this page, 145 00:11:49,340 --> 00:11:54,900 it will always have the same value. So with that, this function shouldn't really be recreated which means 146 00:11:54,900 --> 00:12:00,360 this effect will never rerun unless it's recreated which only is the case if we had a new ID, in which 147 00:12:00,360 --> 00:12:07,820 case it would be good that this is recreated but otherwise, this won't change and hence we should have 148 00:12:07,820 --> 00:12:10,340 a secure communication channel here. 149 00:12:10,550 --> 00:12:16,490 Now in the header, we can now extract that handler, by the way 150 00:12:16,510 --> 00:12:19,040 we also don't need the mealId here anymore, 151 00:12:19,150 --> 00:12:28,420 we can now simply get the toggle favorite function out of our navigation data navigation get param and 152 00:12:28,420 --> 00:12:35,080 then I name that toggle fav, so that's the param name which we can extract and this should give us 153 00:12:35,080 --> 00:12:41,050 access to this function which we pass. Now toggle favorite is what should actually be executed when we 154 00:12:41,050 --> 00:12:42,130 press this button. 155 00:12:42,550 --> 00:12:49,570 So here, I will point at toggle favorite because this holds a pointer at this function and therefore 156 00:12:49,600 --> 00:12:56,740 this function will be executed when we now press this star. Well we'll see if that works. 157 00:12:56,750 --> 00:13:04,760 Let's save that and go back to the spaghetti here and click this star and click to favorites and that 158 00:13:04,760 --> 00:13:05,450 looks good, 159 00:13:05,450 --> 00:13:07,600 spaghetti are part of the favorites. 160 00:13:07,670 --> 00:13:11,440 Let's click the star again here and go to favorites and it's gone, 161 00:13:11,480 --> 00:13:12,730 that makes a lot of sense. 162 00:13:12,740 --> 00:13:18,290 Click it again, it's back, go to the detail page here in the favorites tab and click on the star and 163 00:13:18,290 --> 00:13:20,550 go back, well it's gone. 164 00:13:20,750 --> 00:13:27,410 Let's also verify it on Android, for the schnitzel maybe, favorites is empty right now. Let's go back 165 00:13:27,410 --> 00:13:30,560 and click the star, go to favorites, 166 00:13:30,560 --> 00:13:39,250 here it is, go back, click the star and it's gone. So this logic generally works. 167 00:13:39,250 --> 00:13:43,150 There are a couple of things I still want to work on, for example I want to change the icon based on 168 00:13:43,150 --> 00:13:44,250 the favorite status, 169 00:13:44,260 --> 00:13:49,600 I also want to show some text in the favorite screen when it's empty but generally, dispatching and 170 00:13:49,600 --> 00:13:52,840 using the data works even if we need it in a header.