Day 25 of 100days of code

Photo by RetroSupply on Unsplash

Day 25 of 100days of code

Hello and welcome to day 25 of my challenge!❀πŸ”₯

Building a reusable star rating component.

I'm going to build a reusable StarRating component for the UsePopcorn app. Initially, I'll develop it outside the app as a separate component. Later, I'll integrate it into the UsePopcorn app. First, I'll create a StarRating component within our components folder and render it in Main.jsx instead of the App component. However, this setup is temporary. πŸ‘‡πŸ‘‡

To dynamically generate the star elements, enabling the usage of any number of stars, we enter JavaScript mode on line 5. Utilizing the Array.from method, we create an array with a length of 5. The (_, i) => ... function serves as a callback function for Array.from. It accepts two parameters, but only utilizes the second one (i), representing the index of the current element being created.πŸ‘‡πŸ‘‡

πŸ‘†πŸ‘†I received a warning about the key props, so I'll fix that shortly.

The outputπŸ‘‡πŸ‘‡

I've added some basic inline styles here.πŸ‘‡πŸ‘‡

Now, as a user of this component, for example, if I wanted to pass in a maxRating as props, it would look like thisπŸ‘‡

The result remains the sameπŸ‘‡πŸ‘‡

Now, I'll destructure the maxRating prop and use it in the StarRating component. { length: maxRating } specifies the length of the array to be created. It's an object literal with a single property, length, whose value is set to maxRating. By doing this, it essentially tells Array.from to create an array with a specific length determined by the maxRating prop.πŸ‘‡πŸ‘‡

The output nowπŸ‘‡πŸ‘‡

Now, what if the user decides to use the StarRating component without passing any props?πŸ€”πŸ€”

Here, we need to set a default value for the maxRating, and we can accomplish this by leveraging the power of destructuring.πŸ‘‡πŸ‘‡

Creating the stars and reacting to a click event

To create the Star component, I've included some basic styles and an SVG for the starπŸ‘‡πŸ‘‡

Next, I use the Star component within the StarRating component instead of the span, and I also pass the key prop accordingly.πŸ‘‡

Looks like this nowπŸ‘‡πŸ‘‡

I'm going to improve the accessibility of the span element in the Star component, and this is not specifically related to ReactπŸ‘‡πŸ‘‡

Now to react to a click event πŸ€”:

It sounds like we'll need to utilize some stateπŸ€”πŸ’ͺ

Here, numRating is a state variable created using the useState hook in React. Its initial state is set to 0 using useState(0). Then, we use it in the JSX. This JSX snippet renders a <p> element to display the current value of numRating. The value of numRating is displayed inside the paragraph element. If numRating is falsy (such as 0), an empty string "" is displayed instead. Additionally, an onRate prop is added to the Star component. This prop specifies the function to be called when the Star component is clicked. In this case, an arrow function is used to create an anonymous function that calls setNumRating(i + 1).πŸ‘‡πŸ‘‡πŸ‘‡

Now, to use the onRate prop in the Star componentπŸ‘‡πŸ‘‡

I rated this differently, and the values of the stars showed different ratingsπŸ‘‡πŸ‘‡

Now, to conditionally render the filled star or an empty star:

I've added a prop called full. If this prop is true, the filled star is displayed; otherwise, the empty star is displayed. Since the full prop hasn't been passed into the StarRating component, the empty star is rendered by default. The code conditionally renders different SVG elements based on the value of the full prop: when full is true, the SVG for a filled star is rendered, and when full is false or undefined, the SVG for an empty star is rendered.πŸ‘‡πŸ‘‡

How do we decide whether a star is filled or not:

Now, we create a condition that will evaluate to either true or false. It compares the current rating (numRating) with the index of the star being rendered (i + 1). If the current rating is greater than or equal to the index of the star being rendered, it means that the star should be filled to represent a selected rating. Otherwise, it remains empty to represent an unselected rating. The full prop in this context is used to determine whether the star should be displayed as filled or empty, based on the current rating (numRating) and the index of the star being rendered (i).πŸ‘‡πŸ‘‡

Handling hover events

Now, to add a hover event, we'll create a temporary rating for the number of stars currently being hovered over. It's important to note that this is just temporary, as the onRate value still remains constant.

So, we'll create a new hoverRating state for this purpose.πŸ‘‡πŸ‘‡

Next, I'll create two props onHoverIn and onHoverOut to handle the mouseEnter and mouseLeave events.πŸ‘‡πŸ‘‡

Now, I'll destructure these props in the Star component and add the event listener. It's worth noting that we haven't used the state variable in the JSX just yet.πŸ‘‡πŸ‘‡

Now, I'm going to use this in the JSX and also conditionally render the filled star or empty star.πŸ‘‡πŸ‘‡

Props as a component API

When we build reusable components like this, we should carefully consider which props the component needs. As a component creator, we must think about the component's potential consumers, whether it's ourselves in this case or members of our team if we're collaborating. As the creator, we define the props that the component can receive. The consumer then utilizes the component by specifying values for these props. We can think of the component props as the public API of the component. Just like how a public API defines how external systems or users can interact with a software system, component props define how other components or parts of the application can interact with a reusable component. The props serve as the contract between the component and its consumers, outlining what functionalities are available and how they can be accessed or customized.

Improving reusability with props

Color and Size :

Let's begin with the color and size propsπŸ‘‡πŸ‘‡

Specify default values for the color and size propsπŸ‘‡πŸ‘‡

Now, let's use these props into our text styleπŸ‘‡πŸ‘‡

We'll also pass them as props and utilize them in the Star component for the star style πŸ‘‡πŸ‘‡

Also, we'll use them for the fill colors in the Star componentπŸ‘‡πŸ‘‡

See resultπŸ‘‡πŸ‘‡

To modify some of these default properties, I'll pass in additional propsπŸ‘‡πŸ‘‡

Messages:

This prop is an array of strings, where each string represents a message associated with a particular rating.πŸ‘‡πŸ‘‡

Setting a default valueπŸ‘‡πŸ‘‡

  • Here πŸ‘‡πŸ‘‡, If messages.length === maxRating, it indicates that there is a message provided for each possible rating. In such a scenario, the message corresponding to the selected rating is displayed using the index of the rating (adjusted for zero-based indexing).

    However, if the length of messages doesn't match maxRating, or if messages is not provided, the displayed text defaults to showing the currently hovered rating (hoverRating) if available. Otherwise, it displays the current rating (numRating) if there's no hover interaction.πŸ‘‡πŸ‘‡πŸ‘‡

Thank you for reading❀πŸ’ͺ...

Β