‫Okay, so let's now make
‫our component really flexible and reusable
‫by defining a nice public API for consumers to use it.
‫So right now, our component is quite unflexible
‫and, therefore, not really reusable.
‫So, it might maybe be useful
‫in one very specific case
‫where we want the component to look and behave
‫exactly like this, but it won't be useful
‫for many other consumers.
‫So, if we imagine that we want to reuse this component
‫in many other applications,
‫or maybe even publish it to NPM to share it
‫with all React developers around the world,
‫then they will probably not find this component
‫very useful right now.
‫So those developers, or in other words, those consumers,
‫they will probably want to define things like
‫the colors of these stars
‫or maybe the sizes of the stars and the text
‫in order to basically make this component fit
‫into their own applications.
‫And so, what we're gonna do now is to try to define
‫a good public API for this component
‫just as we learned before.
‫And so, by doing that, we will try to find that balance
‫of using too few props and using too little props
‫so that the component also doesn't get way too complex.
‫So, let's get to work, and let's actually start
‫with those two simple things that I just mentioned,
‫so the color and the size.
‫So, let's just write it here,
‫color
‫and size.
‫And as I mentioned also in the last lecture,
‫it's a good idea to provide default values.
‫So, we already learned that we can do that
‫by providing the default values during destructuring.
‫So, just like we did with the max rating.
‫And so, let's say that our default color
‫will be this yellow of fcc419,
‫and the default size,
‫let's make it the number of 48.
‫Okay, and now, let's use these props in our component,
‫so, to basically accept the color and then change the stars
‫and the text to fit that color.
‫And the same for the size.
‫So, I want to start with the text.
‫And so, now I actually need to take this object here
‫back into the component because now we will specify
‫some properties which will depend on the props.
‫And so the props are, of course, only accessible
‫inside the component.
‫So, then this object will have to live
‫inside the component as well.
‫So, the color property will be set to color,
‫and so, we can actually just do it like this.
‫And if we give this to save,
‫then you see the text does indeed turn yellow.
‫Now, it might be a bit small,
‫and so, let's now also use the size,
‫and so, let's use a template literal
‫and then use the size that we received as a prop
‫and set the pixels to that.
‫Well, that's (laughs) maybe a bit too large.
‫Let's try to divide this, for example, by 1.5
‫and that looks a bit nicer.
‫All right?
‫And now we should also use these values here,
‫of course, for the stars themselves.
‫So, to do that, we will also now place this style object
‫inside the star, and then we need
‫these values also here.
‫So, the color and the
‫size, and so, of course, then we need to pass them
‫in here as props.
‫So color
‫and color
‫and size
‫and size.
‫And so, then here, we can,
‫again, create a template literal,
‫get the size, and then pixels.
‫Let's do the same for the height.
‫And here, nothing changed because
‫we already had 48 here,
‫and now finally, the color is actually defined
‫right in the svgelements.
‫So here, we have to fill and a stroke of black,
‫which is the reason why these are currently black.
‫But if we change that here,
‫like this,
‫so color,
‫then you see that they just turned yellow.
‫Now, of course, this other one isn't yellow yet
‫because, well, it is still at black,
‫so let's change that here as well.
‫Okay,
‫beautiful.
‫So, that's already a lot nicer than before.
‫Let's just call another component here,
‫and let's define
‫some other size here.
‫Let's say 24.
‫And so here we have a much smaller component
‫but which still works in the same way.
‫And, of course, we can also specify the color,
‫let's say red,
‫and so, with this we just made our component
‫a lot more flexible.
‫So, if someone wants to use this component in an application
‫where the main color is red,
‫then they can now easily change all of this to red.
‫Now, sometimes consumers or users of the component
‫want to have even more control over the styling.
‫So, sometimes it's a good idea to allow users
‫to pass in a class name.
‫So, for example, a class name with the name of test,
‫just in this case,
‫which will then come from some CSS file in the application
‫where this component is being used.
‫So right now, we don't have any class like this,
‫but this is just really for testing purposes.
‫So, then here, we need to
‫accept the class name,
‫and by default, it will just be an empty class name,
‫and then, we just edit here to the overall container.
‫So class name
‫and then, class name like this.
‫So, for example, if the user wants to somehow change
‫the font style, they can do that right inside
‫this class name that they pass in,
‫and so, that class name will then be added here.
‫It will then change the font family of our component.
‫Now, another thing that I sometimes see on the web
‫when we have a component like this
‫is that instead of just displaying the rating number,
‫is that they display, like, some message
‫according to the rating.
‫So, in order to do that, we could pass in an array,
‫and let's actually do that here.
‫So, we could pass in an array of messages,
‫for example saying
‫that the first value is terrible,
‫the second one is
‫bad.
‫Then we have, okay,
‫good,
‫well, as a string, and then amazing.
‫And so, now we can display these five values here,
‫so these strings, instead of the numbers.
‫So that's another nice touch
‫that we can give our component here.
‫So then we accept that prop here,
‫and by default, let's make it an empty array.
‫So really, really important to always give default values.
‫And so, now here, we can use those values.
‫However, we want, of course, to only use that messages array
‫in case that there actually are some elements in there.
‫And also the number of elements should be correct.
‫So, for example, if we allow for a rating
‫between one and five, but then we only have three elements
‫in the array, then that doesn't make a lot of sense.
‫So, this wouldn't work.
‫And so, here, what we can do
‫is to just check if messages.length
‫is equal to the maxRating.
‫And if that is the case, then that means
‫that a messages array was passed in.
‫And if not, then we just do exactly what we had before.
‫But in this case, let's then just display the messages
‫at position
‫rating-1
‫in order to convert back to zero-based index.
‫And of course, we should also consider the temporary rating.
‫So let's actually just copy what we have here,
‫or maybe not, (laughs) okay.
‫It's not that similar.
‫So let's come here and say
‫if there is a tempRating,
‫then use
‫tempRating-1,
‫and if not, then just use the regular rating, -1.
‫So again, if this looks confusing,
‫then just make sure to pause the video
‫and analyze that code, but this is just normal JavaScript
‫at this point.
‫But anyway, as you see, this works great now.
‫So, one star means terrible, bad,
‫then it starts to become, okay, good,
‫and finally amazing.
‫And, of course, it also works
‫with the not temporary rating,
‫so at the fixed rating.
‫While here at this other component
‫where the messages array is empty,
‫so that's the default here,
‫so here it's empty, and so, therefore,
‫we are still displaying just the number.
‫Great, and let's keep going because there is still
‫at least one important thing missing
‫and that is to allow the consumer to set a default rating.
‫Okay, so that's not very hard.
‫So, let's say, for example,
‫that the user wants to start with a default of three,
‫defaultRating
‫should be three.
‫So, the consumer might want to specify a prop like this.
‫And so, let's now
‫then add that prop here
‫and give it a default value.
‫Now, by default, the rating should be zero,
‫which is exactly why that's what we put here, right?
‫And so, the default rating
‫should be just that, zero.
‫But of course, now we need to use this defaultRating,
‫and we will use it right here instead of that zero.
‫So basically, we will initialize our rating state
‫with whatever default rating comes into the prop.
‫And if that prop is not specified,
‫then that's simply exactly the zero that we had before.
‫Now, maybe you heard or read that we should never initialize
‫state from props.
‫However, this is only true if you want the state variable
‫to stay in sync with that passed in props,
‫or in other words, if you want the state value
‫to update in case that the prop value is also updated.
‫However, that is clearly not the case here.
‫So, we are really only using this defaultRating here
‫basically as seed data,
‫so really just as the initial state,
‫and we don't care whether this value here
‫maybe changes somewhere else in the application,
‫so outside this component.
‫And, therefore, this is perfectly fine and normal to do.
‫All right, so it's really no problem to initialize
‫your state based on a prop.
‫So I just wanted to address this point
‫because I could already hear some people complaining
‫about this.
‫So this was more relevant in the old days of React
‫before we had hooks, but now,
‫that's really no longer a problem.
‫But anyway, as we save this now,
‫you see that immediately we see the three ratings,
‫or the three stars, as the default here.
‫And, of course, if this was one or two,
‫then that's what we will see there.
‫And so, again, that's just because we are now using
‫this number two as the initial state value of our rating.
‫All right, and now we could keep going here, of course,
‫and add a lot more different props,
‫so, allowing for a lot more configuration.
‫For example, we could say that
‫we want the colors here to change according to the rating,
‫or we could allow for some different spacing
‫between the stars.
‫We could also allow the consumer to specify on
‫which site this text label here appears.
‫So maybe they want it on the left or at the top
‫or at the bottom here,
‫but that might be going a bit too far here
‫and maybe specifying too many props
‫and adding too much complexity.
‫So I think that what we have here right now
‫is more than enough, except for one important thing
‫that we are still missing right now.
‫And that thing is the fact that the consumer
‫might actually need this rating state
‫outside of this component.
‫And to exemplify this, let's come again back here.
‫And what I want to do now, just temporarily,
‫is to create a new component right here, let's call it Test,
‫and so, this component
‫is, then, the one that will include the star rating.
‫And let's say the color in this case is blue.
‫Why not?
‫And then let's also include that down here.
‫And you will see why I'm doing this in this way in a minute.
‫Now, okay, so here we have another one and the blue one,
‫but now let's say that for some reason,
‫they also really needed
‫to display this rating
‫somewhere in their user interface.
‫So, for example, they might have a paragraph
‫saying, "This movie
‫"was rated
‫"X stars."
‫So, here, that's actually already used a maxRating of 10.
‫And so, now what they want to happen is that whatever rating
‫we specify here should then be displayed right here
‫in the user interface.
‫So, now it should say here that the movie was rated
‫seven stars.
‫So, how will they do this right now?
‫So, they basically need access to the state,
‫so to this rating state that we have inside the component
‫but right here, so inside of the test component.
‫So, what they need is some state.
‫So, let's say, "movieRating,"
‫and setMovieRating,
‫and then useState,
‫and let's again set it to zero.
‫And then here, let's use
‫that movie rating.
‫But of course, this now will not change at all
‫when we rate the movie right here.
‫So, we need a way to update this state here
‫whenever the state inside this component is updated as well.
‫So how do we do that?
‫Well, basically, we want to give the consumer
‫of this component the ability to pass in a set function.
‫So, basically, we want them to allow to specify
‫an onSetRating
‫handler.
‫And so, in this case, what this component wants to pass in
‫is simply this function right here.
‫Okay, so let's now specify, then, this prop here.
‫So you want to accept this very important prop right here.
‫And this one by default doesn't need any
‫default value
‫now, right?
‫And now, it's very simple.
‫All we have to do here is, on the handle rating,
‫is to not only set the internal rating,
‫but also to basically set the external rating.
‫So, we can now just say onSetRating.
‫also set that external rating.
‫And with this, we now gave the outside test component,
‫basically, the ability to get access to that internal state
‫right inside this component.
‫Okay, and now, if we change this here,
‫you see that it did, indeed, get updated to seven.
‫So, this additional configuration,
‫so this final prop that we updated here,
‫or that we actually added here to our component,
‫was really, really important
‫because without this, this component would really just be
‫presentational in the end.
‫I mean, it contains some state internally,
‫but from the perspective of the test component,
‫we couldn't really touch that state in any way.
‫And, therefore, we couldn't use that state
‫inside this component, which then, again,
‫wouldn't make this component really useful.
‫Okay, so this was the final prop that we edit,
‫and as I said, we could keep going
‫and get really crazy here
‫with our configuration options.
‫And you could, of course, if you wanted,
‫allow some other things such as the ones
‫that I have mentioned earlier.
‫But we will just leave it as this because I think this,
‫right now, is a pretty good balance.
‫Now, there's just one final thing that we need to do here
‫in our component, which is to prevent the user,
‫basically, to pass in some values that we do not want.
‫So here, for example, this shouldn't be a string, right?
‫'Cause, well, (laughs) then this wouldn't work at all.
‫So we need to make sure that this is actually a number here.
‫And so, let's look at something called prop types
‫in the next lecture.