1 00:00:02,200 --> 00:00:08,590 So let's make sure that our product items on the product overview screen look a bit nicer than they're 2 00:00:08,620 --> 00:00:11,860 currently looking. Right now of course, 00:11.860 -- 00:16.520 every product item is just rendered as a text, as a text component and 3 00:00:16,540 --> 00:00:22,090 that's not what I want here, instead I'll remove that import and I'll create a brand new component that 4 00:00:22,090 --> 00:00:24,970 should be responsible for my product item. 5 00:00:25,060 --> 00:00:31,540 Now one important note regarding where we create that component, we can create it here in the 6 00:00:31,560 --> 00:00:35,510 ProductsOverview.js file as well, we can of course have more than one component per file, 7 00:00:35,530 --> 00:00:41,890 so here I could add my product item component or however you want to call it, like this, 8 00:00:41,890 --> 00:00:47,250 then we can use this component in this file which is of course what I plan to do. 9 00:00:47,290 --> 00:00:52,870 This is a pattern you can use if you have a component that's really strongly tied to another component 10 00:00:53,080 --> 00:00:57,070 and you're only splitting it so that each component is a bit more readable. 11 00:00:57,370 --> 00:01:03,160 Once these separate components get very big, you should still consider splitting them into separate files 12 00:01:03,190 --> 00:01:08,350 though so that your files stay small and if people want to have a look at one of the two components, 13 00:01:08,350 --> 00:01:12,700 they don't have to scroll over the other component they might not be interested in. 14 00:01:12,820 --> 00:01:18,730 So that's one thing to keep in mind. Of course if you also plan on using a component in yet another component, 15 00:01:19,150 --> 00:01:25,990 you should always store it in a separate file, not only so that you can export it as a default because 16 00:01:25,990 --> 00:01:29,950 you could also export this if it's stored along with another component, that's not the main reason 17 00:01:30,520 --> 00:01:36,550 but mostly to make it really clear that this is a standalone component that might and will be used in 18 00:01:36,550 --> 00:01:38,310 different parts of your app. 19 00:01:38,350 --> 00:01:45,550 Now the product item here will not only be not super small which on its own would be a reason to put 20 00:01:45,550 --> 00:01:51,460 it into a separate file but I will also use it in a different component later or in different places 21 00:01:51,460 --> 00:01:57,970 of the app, it's not just relevant to the products overview screen and therefore, I'll add it in the components 22 00:01:57,970 --> 00:02:04,030 folder and in that components folder, to kind of organize my components a little bit, I'll add a shop 23 00:02:04,120 --> 00:02:10,300 subfolder where I want to place all the components that are directly related to the shop feature or 24 00:02:10,300 --> 00:02:12,950 to features in general of my app. 25 00:02:13,090 --> 00:02:19,390 So in there in the shop subfolder, I'll add this ProductItem.js file and you'll see which other 26 00:02:19,390 --> 00:02:21,540 folders I will add here later. 27 00:02:21,550 --> 00:02:27,640 Now again, all these patterns and practices I'm showing you here are just possible ways of doing this, 28 00:02:28,360 --> 00:02:34,480 in general in my courses and in this course too, I show all the best practices you can use but often in programming, 29 00:02:34,480 --> 00:02:37,270 there is not just a single right or wrong way, 30 00:02:37,390 --> 00:02:43,180 so the practices and patterns I'm showing here are practices and patterns you'll see in other projects 31 00:02:43,180 --> 00:02:48,670 too but you might also see other folder structures, in the end you can always work with the structure that 32 00:02:48,670 --> 00:02:55,480 works for you, there isn't a right or wrong choice here, I just want to explain my reasoning for using 33 00:02:55,480 --> 00:03:00,910 this structure which hopefully helps you understand why I use it and why this might be worth a thought. 34 00:03:01,900 --> 00:03:10,960 So here, the product item file, the ProductItem.js file of course will hold the product item component which 35 00:03:10,960 --> 00:03:16,110 is a normal functional component that receives props and in the end will return jsx code and therefore 36 00:03:16,120 --> 00:03:22,750 since it holds jsx code, we need to import React from React and in here, I'll also import things 37 00:03:23,170 --> 00:03:30,070 from React Native because here I'll now work with these React Native primitives to really build my component 38 00:03:30,520 --> 00:03:34,930 because from there, I'll need the view, I'll need the text, I also want to use the image because we'll 39 00:03:34,930 --> 00:03:42,310 display the product image here and also the stylesheet because we'll definitely also style this. Hence 40 00:03:42,310 --> 00:03:48,190 you can also already add a styles constant here which we create with Stylesheet.create to which we 41 00:03:48,190 --> 00:03:56,170 pass a Javascript object and in the end, we export this product item here as a default of course. Now 42 00:03:56,170 --> 00:04:02,350 in here, in this component I mean, we can start creating the jsx code makes up product item and 43 00:04:02,350 --> 00:04:08,500 this will be a presentational component, which means there won't be any logic in here, we won't manage 44 00:04:08,530 --> 00:04:14,630 any internal state, this will just be a component we can use in other components to get the right styling 45 00:04:14,630 --> 00:04:21,250 and layout out of the box, so this component here will be responsible for using certain React Native components 46 00:04:21,400 --> 00:04:28,090 and laying them out and styling them in a certain way. So in here, I in the end want to return a view which 47 00:04:28,090 --> 00:04:34,150 wraps everything, which organizes everything, which we can also style to get this cart look with maybe 48 00:04:34,150 --> 00:04:42,100 a drop shadow, maybe rounded corners, whatever you want and in there, we now have different parts, for 49 00:04:42,100 --> 00:04:50,460 example we'll definitely have the image in there, the product image, I also want to have the title and the 50 00:04:50,460 --> 00:04:53,480 price, so we'll need some text in here, 51 00:04:53,700 --> 00:05:04,630 so for the title here and here, then the for the price in dollars and below that, I also want to have 52 00:05:05,200 --> 00:05:07,650 a view with buttons, 53 00:05:07,650 --> 00:05:14,680 so here we can use the built-in button component for the moment, where we can then add a product to the 54 00:05:14,680 --> 00:05:22,120 cart or also view the details, so where we have these two options basically and of course we'll need 55 00:05:22,120 --> 00:05:26,760 to add onPress handlers here. So that's the very basic skeleton, 56 00:05:26,770 --> 00:05:30,880 probably not the final one, we'll have to see how we can style everything here but 57 00:05:30,930 --> 00:05:32,390 that's the layout I want. 58 00:05:32,500 --> 00:05:37,460 I wrap my buttons here into view by the way because I want to have them side-by-side in the row 59 00:05:37,510 --> 00:05:43,030 and by having a view around them, we can style that view such that it uses flex direction row and 60 00:05:43,040 --> 00:05:43,960 so on. 61 00:05:43,990 --> 00:05:45,040 So that's a setup 62 00:05:45,040 --> 00:05:47,320 we can work with here, 63 00:05:47,440 --> 00:05:49,850 now let's add some styling 64 00:05:49,960 --> 00:05:53,980 and for that I want to use or start here on the surrounding view 65 00:05:53,980 --> 00:05:59,980 where I set up styles product like this, therefore here in the stylesheet, 66 00:05:59,980 --> 00:06:03,900 I add product like that, add my product key here 67 00:06:04,020 --> 00:06:07,200 and of course now again, it's totally up to you how you want to style this, 68 00:06:07,210 --> 00:06:17,650 I want to have that card look, so therefore I'll add a shadow, shadow color which can be black, a shadow opacity 69 00:06:17,650 --> 00:06:27,580 which can be 0.26, a shadow offset where I have the width offset of zero and a height 70 00:06:27,610 --> 00:06:32,080 offset of two and a shadow radius of eight maybe 71 00:06:32,080 --> 00:06:36,490 and as always play around with these values to find your configuration. 72 00:06:36,490 --> 00:06:39,320 Now you might remember that shadow only works on iOS, 73 00:06:39,340 --> 00:06:45,670 so for Android I'll add the elevation property here and set this to five maybe, again you can experiment with 74 00:06:45,670 --> 00:06:48,070 different values there as well 75 00:06:48,160 --> 00:06:52,500 and I want to have a border radius of 10 because I want rounded corners 76 00:06:52,510 --> 00:06:54,250 and again, that's something I want here, 77 00:06:54,250 --> 00:07:00,400 something you don't have to do. I'll also add a background color of white to make sure that our cart here, 78 00:07:00,430 --> 00:07:05,290 our product always has this background color even if our main app should use a different background 79 00:07:05,290 --> 00:07:14,190 color later. So that's my product, my wrapper here around the entire product. I additionally also want 80 00:07:14,190 --> 00:07:16,920 to set up my height here, 81 00:07:16,920 --> 00:07:21,750 every product should have a height of 300 pixels and of course that is a value you can also tweak to 82 00:07:21,750 --> 00:07:22,670 your requirements. 83 00:07:22,740 --> 00:07:28,050 You could of course also make this dynamic with the dimensions API as you learned it in the responsive 84 00:07:28,050 --> 00:07:34,830 module and I'll add a margin of 20 in all directions around every product item, so that we have a spacing 85 00:07:34,860 --> 00:07:42,070 in all directions. With this setup, we can start working on outputting something, 86 00:07:42,230 --> 00:07:47,330 so the image needs a source and we'll get a network image here because if you have a look at the dummy 87 00:07:47,330 --> 00:07:52,940 data, all these image URLs here are URLs, that's also what we have in the model, we 88 00:07:52,940 --> 00:07:54,260 expect a URL here, 89 00:07:54,290 --> 00:07:59,480 so to a network image and that would be the default of course for any shop you build because you'll never 90 00:07:59,480 --> 00:08:06,740 include all the product images into your app, at least if it's not some in app shop for a game but 91 00:08:06,740 --> 00:08:09,070 if it's a shop where people can create products, 92 00:08:09,110 --> 00:08:14,070 obviously people will create products dynamically after your app was distributed, 93 00:08:14,240 --> 00:08:20,300 so it's impossible for you to include all images into your app, instead they have to be stored on a server. 94 00:08:21,450 --> 00:08:26,740 So therefore here, we need to pass an object to source where we set the URI property 95 00:08:26,910 --> 00:08:32,120 and that will now be received from outside because this product item component is presentational, 96 00:08:32,130 --> 00:08:38,060 So any data to display needs to be passed in through props and there, we could expect the image prop 97 00:08:38,070 --> 00:08:40,680 but as for all the props in your own components, 98 00:08:40,680 --> 00:08:47,610 you can pick any names you want. For the title, I expect to get a title prop and for the price, I expect 99 00:08:47,610 --> 00:08:52,740 to get a price prop, I'll keep the dollar sign here by the way because price will just be a number and 100 00:08:52,740 --> 00:08:55,210 of course I want to have a dollar sign in front of this. 101 00:08:55,350 --> 00:09:02,640 Now one little note here, I want to make sure that the price I get always has exactly two decimal places 102 00:09:03,020 --> 00:09:10,520 and we can achieve this by calling to fixed on this and passing in a two. To fixed is a function available 103 00:09:10,560 --> 00:09:17,940 on numbers in Javascript, which converts this to basically a string with a fixed amount of decimal places 104 00:09:17,940 --> 00:09:21,870 and here I restrict this to always be two decimal places, 105 00:09:21,870 --> 00:09:23,210 that's normal Javascript, 106 00:09:23,280 --> 00:09:34,310 nothing specific to React Native. Now when we press the view details button, then I will trigger props 107 00:09:34,400 --> 00:09:41,960 on view detail, so I again use a name here which you can configure or name however you want but the idea 108 00:09:41,960 --> 00:09:47,240 here is that props on view detail points at a function which in the end is executed when this button 109 00:09:47,240 --> 00:09:51,220 is pressed and therefore here, if this button, 110 00:09:51,230 --> 00:09:58,900 the cart button is pressed, I'll point to a function which I expect to get on the on add to cart prop. 111 00:09:58,940 --> 00:09:59,300 Again, 112 00:09:59,540 --> 00:10:03,650 you can name these props whatever you want but when you use your component, you have to make sure they 113 00:10:03,740 --> 00:10:10,370 are available and that they get values which are functions which then are triggered through these buttons. 114 00:10:10,370 --> 00:10:14,300 Now we're getting all the data. Now for the image, since this is a network image, 115 00:10:14,420 --> 00:10:21,440 we need to set up the width and height because the image can't see that in advance as it could do it 116 00:10:21,440 --> 00:10:24,600 for a local image, it can't do this for a network image, 117 00:10:24,620 --> 00:10:31,810 so here I'll point at styles.image and I'll add this image key to my stylesheet there for now. 118 00:10:31,820 --> 00:10:37,790 Again, it's generally up to you how you style this but I'll set this to have a width of let's say 119 00:10:37,790 --> 00:10:38,750 60%, 120 00:10:38,750 --> 00:10:46,580 keep in mind that the overall product has a width of 100% but a height of 60% 121 00:10:46,580 --> 00:10:52,730 because the overall product item here has a height of 300 and I want to have the image in there, 122 00:10:53,000 --> 00:10:58,520 that should also take up the majority of the height but I also have the title and the price and my buttons 123 00:10:58,520 --> 00:10:59,920 and these should also fit in there, 124 00:11:00,020 --> 00:11:02,240 so I'll give the image 60% of the height 125 00:11:02,360 --> 00:11:10,560 so that the other things here can split the remaining 40% amongst them. So with that, that's the image, 126 00:11:10,560 --> 00:11:16,230 now of course the image isn't everything we have here, we also do have our title, we do have our 127 00:11:16,230 --> 00:11:18,800 price and I want to style that as well. 128 00:11:18,840 --> 00:11:24,980 So for the title, I'll add the title style here and for the price, I'll add 129 00:11:25,080 --> 00:11:32,490 let's say a price style and here for these buttons, I'll also add a style to the surrounding view and 130 00:11:32,490 --> 00:11:41,020 I'll name this actions and of course all these style names as always are totally up to you. Here, 131 00:11:41,050 --> 00:11:54,860 I want to add my title and the price and the actions property to my stylesheet here and now 132 00:11:54,860 --> 00:11:59,900 for the title, you can of course style this in whatever way you want. 133 00:11:59,910 --> 00:12:01,970 We have no custom fonts here, 134 00:12:02,070 --> 00:12:05,430 I will add some soon but for the moment, I'll 135 00:12:05,610 --> 00:12:11,610 just ignore that and just start with a font size of 18 and I want to add a margin vertical, so top and 136 00:12:11,610 --> 00:12:21,570 bottom of 3 or 4, so a very small margin but still some margin around this title. For the price, 137 00:12:21,840 --> 00:12:30,490 I'll set a font size of 14 so a bit smaller and I'll also give this a color which should be maybe 888 138 00:12:30,530 --> 00:12:34,380 which is like a grayish, dark grayish color. 139 00:12:34,380 --> 00:12:39,760 Now actions is placed on that view which holds the buttons and therefore, I want to make sure that the 140 00:12:39,760 --> 00:12:42,450 button sit next to each other, so in one row. 141 00:12:42,670 --> 00:12:53,860 So I'll give this a flex direction of row here and I will also justify the content to have all the remaining 142 00:12:53,860 --> 00:13:02,980 space between them and in addition, I want to align items in the center vertically, so along cross axis which 143 00:13:02,980 --> 00:13:06,910 for a flex direction of row is the vertical axis. 144 00:13:06,910 --> 00:13:08,890 With that, we have some basic styling, 145 00:13:08,890 --> 00:13:14,920 now let's use that component before we refine the set up and the styling. So the product item component 146 00:13:14,920 --> 00:13:20,110 which we do export here in the product item file can now be used in the product overview file by 147 00:13:20,110 --> 00:13:22,850 importing product item from there, so 148 00:13:22,870 --> 00:13:29,680 let's point at our components folder, there at the shop subfolder and then the product item 149 00:13:29,680 --> 00:13:35,340 and now this is what I want to use here when I render my items. 150 00:13:35,350 --> 00:13:40,300 Product item can be a self closing component because all the data is received through props and not 151 00:13:40,300 --> 00:13:42,650 between the opening and closing tags, 152 00:13:42,670 --> 00:13:45,340 now of course we need to set up all the things we expect here. 153 00:13:45,340 --> 00:13:50,700 We expect an image, the title, the price and our two event handling props here, 154 00:13:50,710 --> 00:13:52,870 so that's what we need to provide now. 155 00:13:53,560 --> 00:13:55,390 Hence here on product item, 156 00:13:55,510 --> 00:14:02,140 I'll start with the image and that of course is itemData.item.imageUrl and you always must 157 00:14:02,140 --> 00:14:08,800 remember that itemData.item points as a product as defined in our product model and therefore it 158 00:14:08,800 --> 00:14:11,910 will have an imageUrl property written like this, 159 00:14:11,920 --> 00:14:17,980 if you wrote it differently, you of course need to access it differently. Besides the image, we'll also 160 00:14:17,980 --> 00:14:26,290 have a title which is itemData.item.title and besides that, we'll have the price with 161 00:14:26,320 --> 00:14:28,500 itemData.item.price 162 00:14:28,510 --> 00:14:35,140 and then we have our two event handlers here because we do have the on view detail prop and the on add 163 00:14:35,140 --> 00:14:41,470 to cart prop we need to add. So on view detail will do something later, for now it's just an empty function 164 00:14:41,890 --> 00:14:45,150 and on add to cart will also do something later, 165 00:14:45,160 --> 00:14:47,650 for now it can also be an empty function, 166 00:14:47,650 --> 00:14:54,280 this is how our product item should be rendered. With that if we save this, this is what you should see, 167 00:14:54,320 --> 00:14:57,850 it's not perfect yet but we're getting there, 168 00:14:57,860 --> 00:15:01,640 this is not too bad actually. 169 00:15:01,700 --> 00:15:07,300 Now of course what you notice is that the buttons are colored in the wrong way, that this space isn't 170 00:15:07,300 --> 00:15:12,460 really used in the way it should be used down there, that we maybe also want to center this text 171 00:15:12,460 --> 00:15:21,050 but these are of course things we can work on. So to refine this, back in the product item component here, 172 00:15:21,100 --> 00:15:23,900 let's start with our two texts here. 173 00:15:23,950 --> 00:15:30,790 They should of course be centered and that can be done in a very simple way by wrapping that with a 174 00:15:30,790 --> 00:15:37,200 view, moving these two texts in there, giving that view a style 175 00:15:37,250 --> 00:15:38,830 and of course you can name this however you want, 176 00:15:38,840 --> 00:15:43,930 I'll name it details because we kind of layout the product details there, 177 00:15:44,090 --> 00:15:52,710 so I will add my details style here to the stylesheet and there, I'll just set align items center. 178 00:15:52,880 --> 00:16:00,440 This uses a flex direction of column, the default and therefore centers on the cross axis, it always 179 00:16:00,440 --> 00:16:04,870 does this but the cross axis for flex direction column is of course left to right, 180 00:16:04,880 --> 00:16:12,920 so it centers horizontally which is what I want here and I'll also give this a height of 15%. 181 00:16:12,930 --> 00:16:16,830 Keep in mind that the image takes 60%, so we give this maybe 15%, 182 00:16:16,830 --> 00:16:21,070 so almost half of the remaining 40%, not quite half 183 00:16:21,270 --> 00:16:24,960 And I'll add a little bit of padding here of 10 maybe. 184 00:16:24,960 --> 00:16:31,780 And for the buttons here, these are in my actions property, there 185 00:16:31,800 --> 00:16:36,340 I want to set the height to the remaining 25%, 186 00:16:36,550 --> 00:16:41,300 that should be a string of course because we have 60% here height, 187 00:16:41,460 --> 00:16:43,360 then we have 15% here, 188 00:16:43,450 --> 00:16:50,860 hence here I want to keep have the remaining 25% and if we now save this, this looks way better. 189 00:16:50,860 --> 00:16:54,360 Now some padding to the left and right would also be nice for the buttons, 190 00:16:54,370 --> 00:17:01,810 so on this actions style property, I'll add a padding horizontal of 20 maybe, so that we have some internal 191 00:17:01,810 --> 00:17:05,230 spacing left or right. Now to change the color of the buttons, 192 00:17:05,290 --> 00:17:10,540 we can just go to the button components which are built into React Native and set the color prop here 193 00:17:10,550 --> 00:17:12,140 to colors 194 00:17:12,170 --> 00:17:18,250 which you therefore need to import from the constants folder and from the colors file there and set 195 00:17:18,260 --> 00:17:19,530 this then to colors 196 00:17:19,630 --> 00:17:30,510 primary, also here for the second color, the add to cart button, the second button therefore. 197 00:17:30,550 --> 00:17:32,220 So now we have our buttons here, 198 00:17:32,320 --> 00:17:37,090 add to cart and view details and this doesn't look too bad. 199 00:17:37,120 --> 00:17:41,860 The one remaining thing which you might notice is that we don't have rounded corners here at the top 200 00:17:41,860 --> 00:17:48,280 and the reason for that is that our image basically is like an overlay to our background and the background 201 00:17:48,280 --> 00:17:49,570 is the surrounding view, 202 00:17:49,570 --> 00:17:53,800 the image has no rounded corners and therefore it overlaps our rounded corners 203 00:17:53,800 --> 00:17:57,350 we have on the surrounding view. To fix that, 204 00:17:57,520 --> 00:18:01,200 we can wrap the image into a separate view 205 00:18:01,450 --> 00:18:05,580 and as I mentioned earlier in the course, it's really normal in React Native to have a couple of nested 206 00:18:05,580 --> 00:18:13,480 view because to this view, we can now attach a style which we can maybe give an image container identifier 207 00:18:14,080 --> 00:18:20,350 which we can now add to our stylesheet and now I'll give this image container my width and height here 208 00:18:21,040 --> 00:18:24,850 and on the image, I'll therefore just add a width and height of 100% because it's now inside of 209 00:18:24,850 --> 00:18:25,900 the container, 210 00:18:25,950 --> 00:18:27,500 this here refers to the parent, 211 00:18:27,520 --> 00:18:28,750 so to this container, 212 00:18:28,750 --> 00:18:31,970 so a height of 60% will then also be applied to the image 213 00:18:32,110 --> 00:18:35,200 but on that image container, we can now add a border 214 00:18:35,200 --> 00:18:40,200 top left radius of 10 and a border top right radius of 10 215 00:18:40,210 --> 00:18:42,020 so that we round these corners 216 00:18:42,100 --> 00:18:48,520 and now important, add overflow hidden here because this will ensure that any child in there which is 217 00:18:48,520 --> 00:18:53,400 our image of course can't overlap what we set up here. 218 00:18:53,410 --> 00:18:57,960 So now with this setup, we add our rounded corners here back to the top 219 00:18:57,970 --> 00:19:02,860 and now these are the image items I want here and of course that's also a scrollable list 220 00:19:03,070 --> 00:19:08,110 where you also see that these images are lazy loaded automatically which you can continue working with. 221 00:19:08,800 --> 00:19:13,270 Of course, the next goal could be that we can also view the detail screen.