How to Make Star Rating in React
Tags: react, webdev, tutorial
Published: 2023-02-16 22:59:54

For my capstone project at Flatiron School, I created an application in which users can track and manage the eateries (ex: restaurants, cafes/bakeries/coffee shops, & bars/breweries) they have visited and the food and drink they ordered so visits can be referenced at a later time. 

One of the features I wanted to include was a rating functionality. Instead of displaying just numerical ratings, I wanted to display those ratings via star icons. In addition to displaying those numerical ratings into stars, I wanted users to be able to click on the stars to create or edit their rating for an eatery.

I used a React frontend to accomplish this task. I will first describe how to display ratings via stars, and then describe how to dynamically change the star ratings when creating or editing a rating. 

## How to Convert Numerical Rating into Star Rating
Inside the component that holds and displays the eatery rating, I first declared a constant that holds the colors of the stars when they are empty and filled (this can alternatively be done via inline styling). 
```
const colors = {
        orange: "#F2C265",
        grey: "a9a9a9"
    }
```
One of my attributes of an Eatery is the "rating" declared as an integer on the backend. This numerical, integer rating was then translated into stars in React. To create the stars, I first installed the React Icons Kit library and selected the FaStar icon, and imported it into my component. I then created an array of 5 stars, called "stars", where the .fill was 0. 
```
const stars = Array(5).fill(0)
```
Now, in my return, this is where the star rating is displayed on the page. I mapped over the star array and returned the star icon where the color of the star is filled based on the rating of the specific eatery. For example, if a user gave the eatery 4 stars, 4/5 stars would be filled in with the color = orange, and 1/5 stars would remain the color = grey. (I also chose to display the numerical star rating next to the star icons.)
```
return (
  <div>
     {stars.map((_, index) => {
        return (
             <FaStar
                 key={index}
                 size={24}
                 color={(rating) > index ? colors.orange : colors.grey}
              />
      <p>({rating} Stars)</p>
         )
      })}
   </div>
);
```
![Example](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fi8g7vmahw5n5h3kifu3.png)

## How to Dynamically Create and Edit Star Icon Rating
Display a static rating via star icons is more simplistic than creating dynamically changing star icons. Dynamically creating or editing star icon ratings requires useState and event listeners. The same React icon was imported and the same color constant and star array described above were also created. 

First, inside the component where I want to create (or edit) a star icon rating, I created two states. One for the rating attribute, with the initial state set as the current rating (if the user was editing the rating). The other state was created for selecting the stars when rating called "hoverValue". Initial state for the rating attribute was set as the current rating (if the user was editing the rating). Initial state was declared as undefined because we don't want to give the hoverValue a pre-determined state - we want it to be 0 before we start rating. 
```
const [rating, setRating] = useState(eatery.rating)
const [hoverValue, setHoverValue] = useState(undefined)
```
When rating, I wanted to hover over the stars and have them be filled with the orange color before settling on the final rating. To do this, I added a some event listeners to handle this functionality: 
```
const handleMouseOverStar = value => {
    setHoverValue(value)
};

const handleMouseLeaveStar = () => {
    setHoverValue(undefined)
}
```
The handleMouseOver takes in a value when the user hovers over the star icons and sets that value in the setHoverValue setter function. The handleMouseLeaveStar removes the stars when an user moves away from the stars (i.e. wants to reduce the amount of stars they have chosen). 
```
const handleClickStar = value => {
    setRating(value)
};
```
The handleClickStar takes the value of the rating a user choses via a mouse click and sets that value to the setRating setter function. This means, the number of stars a user selects will be the rating of the eatery. 

Now, we need to actually display this functionality on the page. In the return, we are going to map over the stars array (like before) and now include the event listeners. 
```
return (
  <div>
     {stars.map((_, index) => {
          return (
               <FaStar
                   key={index}
                   size={24}
                   value={rating}
                   onChange={(e) => setRating(e.target.value)}
                   color={(hoverValue || rating) > index ? colors.orange : colors.grey}
                   onClick={() => handleClickStar(index + 1)}
                   onMouseOver={() => handleMouseOverStar(index + 1)}
                   onMouseLeave={() => handleMouseLeaveStar}
                />
           )
       })}
  </div>
);
```
The onChange event listener manages the setting of the rating, the onClick event listener manages the incrementation of the star icon rating, and the onMouseOver and onMouseLeave manage the hover effects of the star rating.   

It is difficult to show the functionality of this hover star rating via images, but if you are curious how this works, you can play around with it on my website: {% embed https://leftovers-2mnc.onrender.com/ %}

I think this functionality is a fun feature to add to any website that includes rating, and I hope this tutorial was helpful!