So let's make sure that our product items on the product overview screen look a bit nicer than they're
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
that's not what I want here, instead I'll remove that import and I'll create a brand new component that
should be responsible for my product item.
Now one important note regarding where we create that component, we can create it here in the
ProductsOverview.js file as well, we can of course have more than one component per file,
so here I could add my product item component or however you want to call it, like this,
then we can use this component in this file which is of course what I plan to do.
This is a pattern you can use if you have a component that's really strongly tied to another component
and you're only splitting it so that each component is a bit more readable.
Once these separate components get very big, you should still consider splitting them into separate files
though so that your files stay small and if people want to have a look at one of the two components,
they don't have to scroll over the other component they might not be interested in.
So that's one thing to keep in mind. Of course if you also plan on using a component in yet another component,
you should always store it in a separate file, not only so that you can export it as a default because
you could also export this if it's stored along with another component, that's not the main reason
but mostly to make it really clear that this is a standalone component that might and will be used in
different parts of your app.
Now the product item here will not only be not super small which on its own would be a reason to put
it into a separate file but I will also use it in a different component later or in different places
of the app, it's not just relevant to the products overview screen and therefore, I'll add it in the components
folder and in that components folder, to kind of organize my components a little bit, I'll add a shop
subfolder where I want to place all the components that are directly related to the shop feature or
to features in general of my app.
So in there in the shop subfolder, I'll add this ProductItem.js file and you'll see which other
folders I will add here later.
Now again, all these patterns and practices I'm showing you here are just possible ways of doing this,
in general in my courses and in this course too, I show all the best practices you can use but often in programming,
there is not just a single right or wrong way,
so the practices and patterns I'm showing here are practices and patterns you'll see in other projects
too but you might also see other folder structures, in the end you can always work with the structure that
works for you, there isn't a right or wrong choice here, I just want to explain my reasoning for using
this structure which hopefully helps you understand why I use it and why this might be worth a thought.
So here, the product item file, the ProductItem.js file of course will hold the product item component which
is a normal functional component that receives props and in the end will return jsx code and therefore
since it holds jsx code, we need to import React from React and in here, I'll also import things
from React Native because here I'll now work with these React Native primitives to really build my component
because from there, I'll need the view, I'll need the text, I also want to use the image because we'll
display the product image here and also the stylesheet because we'll definitely also style this. Hence
you can also already add a styles constant here which we create with Stylesheet.create to which we
pass a Javascript object and in the end, we export this product item here as a default of course. Now
in here, in this component I mean, we can start creating the jsx code makes up product item and
this will be a presentational component, which means there won't be any logic in here, we won't manage
any internal state, this will just be a component we can use in other components to get the right styling
and layout out of the box, so this component here will be responsible for using certain React Native components
and laying them out and styling them in a certain way. So in here, I in the end want to return a view which
wraps everything, which organizes everything, which we can also style to get this cart look with maybe
a drop shadow, maybe rounded corners, whatever you want and in there, we now have different parts, for
example we'll definitely have the image in there, the product image, I also want to have the title and the
price, so we'll need some text in here,
so for the title here and here, then the for the price in dollars and below that, I also want to have
a view with buttons,
so here we can use the built-in button component for the moment, where we can then add a product to the
cart or also view the details, so where we have these two options basically and of course we'll need
to add onPress handlers here. So that's the very basic skeleton,
probably not the final one, we'll have to see how we can style everything here but
that's the layout I want.
I wrap my buttons here into view by the way because I want to have them side-by-side in the row
and by having a view around them, we can style that view such that it uses flex direction row and
so on.
So that's a setup
we can work with here,
now let's add some styling
and for that I want to use or start here on the surrounding view
where I set up styles product like this, therefore here in the stylesheet,
I add product like that, add my product key here
and of course now again, it's totally up to you how you want to style this,
I want to have that card look, so therefore I'll add a shadow, shadow color which can be black, a shadow opacity
which can be 0.26, a shadow offset where I have the width offset of zero and a height
offset of two and a shadow radius of eight maybe
and as always play around with these values to find your configuration.
Now you might remember that shadow only works on iOS,
so for Android I'll add the elevation property here and set this to five maybe, again you can experiment with
different values there as well
and I want to have a border radius of 10 because I want rounded corners
and again, that's something I want here,
something you don't have to do. I'll also add a background color of white to make sure that our cart here,
our product always has this background color even if our main app should use a different background
color later. So that's my product, my wrapper here around the entire product. I additionally also want
to set up my height here,
every product should have a height of 300 pixels and of course that is a value you can also tweak to
your requirements.
You could of course also make this dynamic with the dimensions API as you learned it in the responsive
module and I'll add a margin of 20 in all directions around every product item, so that we have a spacing
in all directions. With this setup, we can start working on outputting something,
so the image needs a source and we'll get a network image here because if you have a look at the dummy
data, all these image URLs here are URLs, that's also what we have in the model, we
expect a URL here,
so to a network image and that would be the default of course for any shop you build because you'll never
include all the product images into your app, at least if it's not some in app shop for a game but
if it's a shop where people can create products,
obviously people will create products dynamically after your app was distributed,
so it's impossible for you to include all images into your app, instead they have to be stored on a server.
So therefore here, we need to pass an object to source where we set the URI property
and that will now be received from outside because this product item component is presentational,
So any data to display needs to be passed in through props and there, we could expect the image prop
but as for all the props in your own components,
you can pick any names you want. For the title, I expect to get a title prop and for the price, I expect
to get a price prop, I'll keep the dollar sign here by the way because price will just be a number and
of course I want to have a dollar sign in front of this.
Now one little note here, I want to make sure that the price I get always has exactly two decimal places
and we can achieve this by calling to fixed on this and passing in a two. To fixed is a function available
on numbers in Javascript, which converts this to basically a string with a fixed amount of decimal places
and here I restrict this to always be two decimal places,
that's normal Javascript,
nothing specific to React Native. Now when we press the view details button, then I will trigger props
on view detail, so I again use a name here which you can configure or name however you want but the idea
here is that props on view detail points at a function which in the end is executed when this button
is pressed and therefore here, if this button,
the cart button is pressed, I'll point to a function which I expect to get on the on add to cart prop.
Again,
you can name these props whatever you want but when you use your component, you have to make sure they
are available and that they get values which are functions which then are triggered through these buttons.
Now we're getting all the data. Now for the image, since this is a network image,
we need to set up the width and height because the image can't see that in advance as it could do it
for a local image, it can't do this for a network image,
so here I'll point at styles.image and I'll add this image key to my stylesheet there for now.
Again, it's generally up to you how you style this but I'll set this to have a width of let's say
60%,
keep in mind that the overall product has a width of 100% but a height of 60%
because the overall product item here has a height of 300 and I want to have the image in there,
that should also take up the majority of the height but I also have the title and the price and my buttons
and these should also fit in there,
so I'll give the image 60% of the height
so that the other things here can split the remaining 40% amongst them. So with that, that's the image,
now of course the image isn't everything we have here, we also do have our title, we do have our
price and I want to style that as well.
So for the title, I'll add the title style here and for the price, I'll add
let's say a price style and here for these buttons, I'll also add a style to the surrounding view and
I'll name this actions and of course all these style names as always are totally up to you. Here,
I want to add my title and the price and the actions property to my stylesheet here and now
for the title, you can of course style this in whatever way you want.
We have no custom fonts here,
I will add some soon but for the moment, I'll
just ignore that and just start with a font size of 18 and I want to add a margin vertical, so top and
bottom of 3 or 4, so a very small margin but still some margin around this title. For the price,
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
which is like a grayish, dark grayish color.
Now actions is placed on that view which holds the buttons and therefore, I want to make sure that the
button sit next to each other, so in one row.
So I'll give this a flex direction of row here and I will also justify the content to have all the remaining
space between them and in addition, I want to align items in the center vertically, so along cross axis which
for a flex direction of row is the vertical axis.
With that, we have some basic styling,
now let's use that component before we refine the set up and the styling. So the product item component
which we do export here in the product item file can now be used in the product overview file by
importing product item from there, so
let's point at our components folder, there at the shop subfolder and then the product item
and now this is what I want to use here when I render my items.
Product item can be a self closing component because all the data is received through props and not
between the opening and closing tags,
now of course we need to set up all the things we expect here.
We expect an image, the title, the price and our two event handling props here,
so that's what we need to provide now.
Hence here on product item,
I'll start with the image and that of course is itemData.item.imageUrl and you always must
remember that itemData.item points as a product as defined in our product model and therefore it
will have an imageUrl property written like this,
if you wrote it differently, you of course need to access it differently. Besides the image, we'll also
have a title which is itemData.item.title and besides that, we'll have the price with
itemData.item.price
and then we have our two event handlers here because we do have the on view detail prop and the on add
to cart prop we need to add. So on view detail will do something later, for now it's just an empty function
and on add to cart will also do something later,
for now it can also be an empty function,
this is how our product item should be rendered. With that if we save this, this is what you should see,
it's not perfect yet but we're getting there,
this is not too bad actually.
Now of course what you notice is that the buttons are colored in the wrong way, that this space isn't
really used in the way it should be used down there, that we maybe also want to center this text
but these are of course things we can work on. So to refine this, back in the product item component here,
let's start with our two texts here.
They should of course be centered and that can be done in a very simple way by wrapping that with a
view, moving these two texts in there, giving that view a style
and of course you can name this however you want,
I'll name it details because we kind of layout the product details there,
so I will add my details style here to the stylesheet and there, I'll just set align items center.
This uses a flex direction of column, the default and therefore centers on the cross axis, it always
does this but the cross axis for flex direction column is of course left to right,
so it centers horizontally which is what I want here and I'll also give this a height of 15%.
Keep in mind that the image takes 60%, so we give this maybe 15%,
so almost half of the remaining 40%, not quite half
And I'll add a little bit of padding here of 10 maybe.
And for the buttons here, these are in my actions property, there
I want to set the height to the remaining 25%,
that should be a string of course because we have 60% here height,
then we have 15% here,
hence here I want to keep have the remaining 25% and if we now save this, this looks way better.
Now some padding to the left and right would also be nice for the buttons,
so on this actions style property, I'll add a padding horizontal of 20 maybe, so that we have some internal
spacing left or right. Now to change the color of the buttons,
we can just go to the button components which are built into React Native and set the color prop here
to colors
which you therefore need to import from the constants folder and from the colors file there and set
this then to colors
primary, also here for the second color, the add to cart button, the second button therefore.
So now we have our buttons here,
add to cart and view details and this doesn't look too bad.
The one remaining thing which you might notice is that we don't have rounded corners here at the top
and the reason for that is that our image basically is like an overlay to our background and the background
is the surrounding view,
the image has no rounded corners and therefore it overlaps our rounded corners
we have on the surrounding view. To fix that,
we can wrap the image into a separate view
and as I mentioned earlier in the course, it's really normal in React Native to have a couple of nested
view because to this view, we can now attach a style which we can maybe give an image container identifier
which we can now add to our stylesheet and now I'll give this image container my width and height here
and on the image, I'll therefore just add a width and height of 100% because it's now inside of
the container,
this here refers to the parent,
so to this container,
so a height of 60% will then also be applied to the image
but on that image container, we can now add a border
top left radius of 10 and a border top right radius of 10
so that we round these corners
and now important, add overflow hidden here because this will ensure that any child in there which is
our image of course can't overlap what we set up here.
So now with this setup, we add our rounded corners here back to the top
and now these are the image items I want here and of course that's also a scrollable list
where you also see that these images are lazy loaded automatically which you can continue working with.
Of course, the next goal could be that we can also view the detail screen.