Build a Rating App With React & Strapi
Tags: strapi, react, cms, apps
Published: 2021-10-27 14:20:08

## Introduction

In this tutorial, you will learn how to build a rating app with react and Strapi. This is relatively straightforward as we'll be able to give our ratings, reviews and also be able to display them on our webpage. First, let's take a sneak pick into React and Strapi.

## What is React?

React is a library for building user interfaces. It runs on the client as a SPA(single page app) but can also build full-stack apps by communicating with a server/API. React is often referred to as a frontend "framework" because it is capable and directly comparable to a framework such as Angular or Vue.

## Why should you try it out
- It structures the "view" layer of your application.
- Reusable components with their state.
- JSX-Dynamic markup.
- Interactive UIs with virtual DOM.
- Performance and testing.
- Very popular in the industry.

## What is Strapi?

Strapi is an open-source CMS that allows you to build customizable APIs in any frontend application. Strapi is so easy to work with as it will enable you to build flexible APIs with unique features you'll love. You can create custom content types and relationships between the content types so that things can stay organized. It also gives you a media library where you can host your image or audio assets.
Now that we have an understanding of both. Let's get started.

## Overview
- Introduction
- What is React?
- What is Strapi?
- Prerequisites
- Requirements
- Installing Strapi
- Creating the frontend
- Fetching our API
- Creating reviews
- Conclusion

## Prerequisites
- Basic understanding of JavaScript
- Basic understanding of ReactJS

## Requirements
- Npm
- React icons which we would install along with our react app
- Axios

## Installing Strapi 

We first need to go to our terminal and navigate the project folder you want Strapi to be installed. Strapi can be installed either with Yarn or NPX.

Yarn command: 

```bash
    yarn create strapi-app rating-app --quickstart
```

npx command:

```bash
    npx create-strapi-app rating-app --quickstart
```

 
This will install all the needed packages for this project. After the installation, our Strapi app will automatically be launched in our browser. We should have something like this:
 

![](https://paper-attachments.dropbox.com/s_9083DA9AF92541E44AF409D7321F6F54BECE0A8D09A283ABCE21500393E074CC_1634605700234_strapi+welcome.JPG)


To finish up, create admin by signing up.  Now that we've created our Strapi, let's head over to the `content-type builder` link. 


![](https://paper-attachments.dropbox.com/s_9083DA9AF92541E44AF409D7321F6F54BECE0A8D09A283ABCE21500393E074CC_1634609548988_content+type.JPG)


 You'll see three different headings, namely

-   Collection types
-   Single types
-   Component

Collection types are what we're interested in. These are types that we'll have more than one of on our website. A single type would be for a unique piece of content, for example, a homepage that might have a title and about section. A component is just a collection of fields that you might use in many different types.


![](https://paper-attachments.dropbox.com/s_9083DA9AF92541E44AF409D7321F6F54BECE0A8D09A283ABCE21500393E074CC_1634609748033_collection+type.JPG)


Click on collection types, give it a display name, and make sure it's singular, not plural. Strapi automatically pluralizes it. We will call our collection `review`.

![](https://paper-attachments.dropbox.com/s_9083DA9AF92541E44AF409D7321F6F54BECE0A8D09A283ABCE21500393E074CC_1634609841754_create+collection.JPG)


Next, we have to define a field and field type. For our reviews, we want a `title` field that is of type `text`. Then we give the field a name called `Name`. It can be `short text` or `long text`. The `short text` is best for the title.


![](https://paper-attachments.dropbox.com/s_9083DA9AF92541E44AF409D7321F6F54BECE0A8D09A283ABCE21500393E074CC_1634610041902_field.JPG)


 
Click on the advanced setting and make it a required field or a unique field so that no two review titles can be the same. 

Click on add another field. Now we need a rating field that will be a number, so go ahead and click the number and give this the name of `Rating` and then choose a number format. Ours will be an `integer`.
 

![](https://paper-attachments.dropbox.com/s_9083DA9AF92541E44AF409D7321F6F54BECE0A8D09A283ABCE21500393E074CC_1634610315961_number+field.JPG)


We then go to advance setting and make it required and add a minimum value of 1 and a max value that will be 5, so this field can only be a number from one to 5.
 
Let's add another field for the body, and that's going to be rich text to add formats into it. Click on it and give it a name called `reviews` we could go to the advanced and make it required, and now we could click on finish.


![](https://paper-attachments.dropbox.com/s_9083DA9AF92541E44AF409D7321F6F54BECE0A8D09A283ABCE21500393E074CC_1634902320816_file.jpeg)

![](https://paper-attachments.dropbox.com/s_9083DA9AF92541E44AF409D7321F6F54BECE0A8D09A283ABCE21500393E074CC_1634610597656_rich+text+2.JPG)


So now we have all the different fields for our content-type reviews. Click save to save our reviews. Next, we head over to settings. Navigate to `Roles` and click on the `public`. We then scroll down to permissions and click on `select all`.


![](https://paper-attachments.dropbox.com/s_9083DA9AF92541E44AF409D7321F6F54BECE0A8D09A283ABCE21500393E074CC_1634610729870_role2.JPG)


Strapi saves and refreshes the browser. Now that it's done, we can see the content type review, and if we click on that, we can see our empty review list. 

Let's click on add new reviews and then add reviews(I'll add up to 4 reviews in the list), then click on `publish` after filling out the fields.


![Capture d’écran 2021-10-27 à 15.06.07.png](/uploads/Capture_d_ecran_2021_10_27_a_15_06_07_e97675d75e.png)


So if we try to retrieve it by using the Strapi API, It sends us the data.

**To start your Strapi app always run:**

```bash
    npm run develop
```

If you got it up to this part, you're a genius!!! Now let's move to the next step, which is creating the front end.

## Creating the front end

As earlier stated, React would be used as our frontend. So let's go ahead and install React and all the packages we'll need. Let's open up our terminal once more and navigate the folder where we want to install react. 

Run the command:

```bash
    npx create react-app react-ratings
```

Next, navigate to the folder where we just installed React.

```
    cd react-ratings
```

Next, we want to install React icons.

```bash
    npm install react-icons
```

And lastly, let’s install Axios.

```bash
    npm install axios
```

Now that's done, let's remove and edit the things we don't want in our react app. First of all, let's delete all the files highlighted in the image below as we won't be needing them.


![](https://paper-attachments.dropbox.com/s_9083DA9AF92541E44AF409D7321F6F54BECE0A8D09A283ABCE21500393E074CC_1634612524168_delete.JPG)


 
Also, we'll head to our `app.js` and remove the  `import from '.logo.svg';` the `import './app.css'`.


![](https://paper-attachments.dropbox.com/s_9083DA9AF92541E44AF409D7321F6F54BECE0A8D09A283ABCE21500393E074CC_1634612609479_delete2.JPG)


Next, we will also delete the headers in our `App()` function. 


![](https://paper-attachments.dropbox.com/s_9083DA9AF92541E44AF409D7321F6F54BECE0A8D09A283ABCE21500393E074CC_1634612627138_delete3.JPG)


Next, head over to head `index.js` and delete the `import reportWebvitals  from` `./reportWebvitals`; the `import` `.index.css`; and `reportWebvitals()` .  The final look of our `index.js` should be like this:

![](https://paper-attachments.dropbox.com/s_9083DA9AF92541E44AF409D7321F6F54BECE0A8D09A283ABCE21500393E074CC_1634811336081_real+look.JPG)


 
Now that we are done let’s start our  react app:

```bash
    npm start
```


We'll see a blank page. This means we are on the right track.

## Reading and fetching our reviews.

First we create a folder in our `src` folder, name it api, next we create a file inside called `index.js` and add the following codes to it:

```
    import axios from 'axios';
    const url = "http://localhost:1337/reviews";
    export const readReviews = ()=>axios.get(url);
    export const createReview = newReview =>axios.post(url,newReview);
```


This includes explanations:


- Importing Axios to our app.
- The path to our API.
- Creating reviews(adding data to our or review API via webpage).
- Reading the reviews data.


Axios will be responsible for fetching data from our API and also adding to it. We then go back to our `app.js` and import the just created API folder containing the `index.js` to our app:

```
    import * as api from "./api";
```


We also be using bootstrap so let’s copy the bootstrap link to our `index.html` in our public folder.


    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">

Now we have everything to start building.

## Fetching  our API

To do this, we are going to be using the **useState** and the **useEffect**. The `useState` will allow us to state variables, while the `useEffect` will fulfill our parameters in our components when it renders.

Let’s head over `app.js` and write the following at the top:

```
    import React, { useState, useEffect } from "react";
    import { FaStar } from "react-icons/fa";
    const colors = {
      orange: "#FFBA5A",
      grey: "#a9a9a9",
    };
```

 
Under our function `app()` in our `app.js` we write this:

```
    const [review, setReview] = useState({});
      const [reviews, setReviews] = useState([]);
      useEffect(
        () => {
          const fetchData = async () => {
            const result = await api.readReviews();
     
            setReviews(result.data);
          };
          fetchData();
              },[])
                  )
```

 
Next, lets create the contents where our API will be displayed

```
     <section id="reviews">
            <div class="reviews-heading">
              <span>REVIEWS FROM CUSTOMERS</span>
            </div>
            <div className="container">
              <div className="row">
                  <div className="col-md-6">
                    <div class="reviews-box">
                      <div class="box-top">
                        <div class="profile">
                          <div class="name-user">
                            <strong>Temitope</strong>
                          </div>
                        </div>
                            <FaStar key={i} size={18} color={colors.orange} />
                        </div>
                      </div>
                   <div class="client-comment">lorem ipsum lorem ipsumlorem ipsumvvvlorem ipsumlorem ipsumlorem ipsumlorem ipsum </div>
                    </div>
                  </div>
              </div>
            </div>
          </section>
```

            
If you encounter an error saying `jsx must have one parent element`. Do not worry. We can fix this by using `<React.Fragment/> or simply use the short syntax <></>`.

Let's give it a styling. Create a folder under the `src` folder and name it `styles`, then create a file and name it anything you like. Add the following codes to it:
 
```
     *{
      margin: 0px;
      padding: 0px;
      font-family: poppins;
      box-sizing: border-box;
    }
    a{
      text-decoration: none;
    }
    #reviews{
      display: flex;
      justify-content: center;
      align-items: center;
      flex-direction: column;
      width:100%;
    }
    .reviews-heading{
      letter-spacing: 1px;
      margin: 30px 0px;
      padding: 10px 20px;
      display: flex;
      flex-direction: column;
      justify-content: center;
      align-items: center;
    }
     
    .reviews-heading span{
      font-size: 1.3rem;
      color: #252525;
      margin-bottom: 10px;
      letter-spacing: 2px;
      text-transform: uppercase;
    }
    .reviews-box-container{
      display: flex;
      justify-content: center;
      align-items: center;
      flex-wrap: wrap;
      width:100%;
    }
    .reviews-box{
      width:500px;
      box-shadow: 4px 4px 40px rgba(0,0,0,0.1);
      background-color: #ffffff;
      padding: 20px;
      margin: 15px;
      cursor: pointer;
    }
     
    .name-user{
      display: flex;
      flex-direction: column;
    }
    .name-user strong{
      color: #3d3d3d;
      font-size: 1.1rem;
      letter-spacing: 0.5px;
    }
    .name-user span{
      color: #979797;
      font-size: 0.8rem;
    }
     
    .box-top{
      display: flex;
      justify-content: space-between;
      align-items: center;
      margin-bottom: 20px;
    }
    .client-comment p{
      font-size: 0.9rem;
      color: #4b4b4b;
    }
    .reviews-box:hover{
      transform: translateY(-10px);
      transition: all ease 0.3s;
    }
     
    @media(max-width:1060px){
      .reviews-box{
          width:45%;
          padding: 10px;
      }
    }
    @media(max-width:790px){
      .reviews-box{
          width:100%;
      }
      .reviews-heading h1{
          font-size: 1.4rem;
      }
    }
    @media(max-width:340px){
      .box-top{
          flex-wrap: wrap;
          margin-bottom: 10px;
      }
      .reviews{
          margin-top: 10px;
      }
    }
    ::selection{
      color: #ffffff;
      background-color: #252525;
    }
```


Head back to `app.js` and import the CSS:

```
    import "./styles/review_style.css";
```

 
Now that we've done that let's start adding API values to our contents. Under the the div class `row` add this code:

```
    {reviews.map((review, i) => (
```

 
 Close it before the last two divs
 
```
      ))}
```


The `.map` function helps us to iterate our list of data.

For our name, we go to where we wrote name (between our strong tags) and replace it with this:
 
```
    {review.Name}
```


 
To display our rating, replace it with this code:

```
     {Array.from({ length: review.Rating }).map((i) => (
                            <FaStar key={i} size={18} color={colors.orange} />
                          ))}
```

Lastly, for our reviews, we change the dummy texts with:

```
    {review.review}
```

 
If you’re confused at this stage, copy and paste this the code below and you should get right back on track.

```
     <section id="reviews">
            <div class="reviews-heading">
              <span>REVIEWS FROM CUSTOMERS</span>
            </div>
     
            <div className="container">
              <div className="row">
                {reviews.map((review, i) => ( // calling the api
                  <div className="col-md-6">
                    <div class="reviews-box">
                      <div class="box-top">
                        <div class="profile">
                          <div key={i}></div>
                          <div class="name-user">
                            <strong>{review.Name}</strong>
                          </div>
                        </div>
     
                        <div style={styles.stars}>
                          {Array.from({ length: review.Rating }).map((i) => (
                            <FaStar key={i} size={18} color={colors.orange} />
                          ))}
                        </div>
                      </div>
                      <div class="client-comment">{review.review}</div>
                    </div>
                  </div>
                ))}
              </div>
            </div>
          </section>
```


 
Now that we're done, we should be able to view our review API.

## Creating reviews

Now let’s create a form for rating and reviewing. Write the following code in our function app() above our section displaying our reviews.

```
    <div style={styles.container}>
      <h2>star ratings app in react</h2>
          <div style ={styles.stars}>
          {stars.map((_, index) => {
            return(
              <FaStar
                key={index}
                size ={24}
                style={{
                  marginRight :10,
                  cursor:"pointer"
                }} 
                color ={(hoverValue || currentValue)> index ? colors.orange : colors.grey}
                onClick={() => handleClick(index + 1)}
                onMouseOver={()=> handleMouseOver(index + 1)}
                
              />
            )
          })}
        </div>
    <div>
                <input
                  type="text"
                  placeholder="input your name"
                  required
                  style={styles.input />
              </div>
     
        <textarea
         placeholder="what's your feedback"
         style={styles.textarea}
        />
        <button style={styles.button}>submit</button>
          </div>
```

    
Input this code above the form just after our function `app()`:

```
    const stars = Array(5).fill(0);
      const [currentValue, setCurrentValue] = React.useState(0);
      const [hoverValue, setHoverValue] = React.useState(undefined);
      const handleClick = (value) => {
        setCurrentValue(value);
      };
      const handleMouseOver = (value) => {
        setHoverValue(value);
      };
```

     
We then add an inline css to it. This should be written below just before the export default app.

```
    const styles = {
    container: {
        align: "center",
        display: "flex",
        flexDirection: "column",
        alignItems: "center",
        boxShadow: "0 0 20px 0 #999",
        width: "30%",
        margin: "50px auto",
        flexDirection: "column",
      },
      input: {
        borderRaduis: 5,
        width: 300,
        margin: "10px 0",
        marginDown: "15px",
        minHeight: 30,
        padding: 1,
        height: "20px",
      },
      textarea: {
        border: "1px solid #a9a9a9",
        borderRaduis: 5,
        width: 300,
        margin: "20px 0",
        minHeight: 100,
        padding: 10,
      },
     
      button: {
        border: "1px solid #a9a9a9",
        borderRaduis: 5,
        width: 300,
        padding: 10,
        margin: "20px 0",
      },
    };
```


 
Inside star icons(fastar), replace the `onClick` function we wrote with:

```
     onClick={() => {
                        setReview({ ...review, Rating: index + 1 });
                      }}
```


 
Next add the following inside our input tag:

```
    value={review.Name}
                  onChange={(e) => setReview({ ...review, Name: e.target.value })}
```

 
We will also add to text area and button. For text area:

```
    value={review.review}
                onChange={(e) => setReview({ ...review, review: e.target.value })}
```


and lastly, for button:

```
     onClick={createReview}
```

 
Confused? Here’s the full code for the form.

```
     <form>
    <div style={styles.container}>
              <h2>RATE OUR SERVICE</h2>
     
              <div style={styles.stars}>
                {stars.map((_, index) => {
                  return (
                    <FaStar
                      key={index}
                      size={24}
                      style={{
                        marginRight: 10,
                        cursor: "pointer",
                      }}
                      color={
                        (hoverValue || currentValue) > index
                          ? colors.orange
                          : colors.grey
                      }
                      onClick={() => {
                        setReview({ ...review, Rating: index + 1 });
                      }}
                      onMouseOver={() => handleMouseOver(index + 1)}
                    />
                  );
                })}
              </div>
              <div>
                <input
                  type="text"
                  placeholder="input your name"
                  required
                  style={styles.input}
                  value={review.Name}
                  onChange={(e) => setReview({ ...review, Name: e.target.value })}
                />
              </div>
     
              <textarea
                placeholder="what's your feedback"
                required
                style={styles.textarea}
                value={review.review}
                onChange={(e) => setReview({ ...review, review: e.target.value })}
              />
              <button
                type="submit"
                style={styles.button}
                class="btn btn-primary"
                onClick={createReview}
              >
                submit
              </button>
            </div>
          </form>
```


     
We’re almost done. Let’s scroll up and type the following below our use effect code:

```
      const createReview = async () => {
      try {
          console.log(review);
          const data = await api.createReview(review);
          setReview([...reviews, data]);
        } catch (error) {
          console.log(error);
        }
      };
      let [reviewCount, setreviewCount] = useState([]);
      const setCountFxn = (no) => {
        setReview(no);
      };
     
          const data = await api.createReview(review);
          setReview([...reviews, data]);
        } catch (error) {
          console.log(error);
        }
      };
      let [reviewCount, setreviewCount] = useState([]);
      const setCountFxn = (no) => {
        setReview(no);
      };
```
     

 
Now we're done. Suppose you get an error that's because you didn't add the tag `<></>` like I earlier suggested(don't add if you're not getting an error). 

Here's the complete code of `app.js`. You have to edit them to do your values.

```
    import React, { useState, useEffect } from "react";
    import * as api from "./api";
    import "./styles/review_style.css";
    import { FaStar } from "react-icons/fa";
    const colors = {
      orange: "#FFBA5A",
      grey: "#a9a9a9",
    };
     
    function App() {
      const stars = Array(5).fill(0);
      const [currentValue, setCurrentValue] = React.useState(0);
      const [hoverValue, setHoverValue] = React.useState(undefined);
     
      const handleClick = (value) => {
        setCurrentValue(value);
      };
     
      const handleMouseOver = (value) => {
        setHoverValue(value);
      };
     
      const handleMouseLeave = () => {
        setHoverValue(undefined);
      };
      const [review, setReview] = useState({});
      const [reviews, setReviews] = useState([]);
      useEffect(
        () => {
          const fetchData = async () => {
            const result = await api.readReviews();
            // console.log(result);
            setReviews(result.data);
          };
          fetchData();
     
          
        },
        
        []
      );
      const createReview = async () => {
        try {
          console.log(review);
          const data = await api.createReview(review);
          setReview([...reviews, data]);
        } catch (error) {
          console.log(error);
        }
      };
      let [reviewCount, setreviewCount] = useState([]);
      const setCountFxn = (no) => {
        setReview(no);
      };
      return (
        <>
          <form>
            <div style={styles.container}>
              <h2>RATE OUR SERVICE</h2>
     
              <div style={styles.stars}>
                {stars.map((_, index) => {
                  return (
                    <FaStar
                      key={index}
                      size={24}
                      style={{
                        marginRight: 10,
                        cursor: "pointer",
                      }}
                      color={
                        (hoverValue || currentValue) > index
                          ? colors.orange
                          : colors.grey
                      }
                      onClick={() => {
                        setReview({ ...review, Rating: index + 1 });
                      }}
                      onMouseOver={() => handleMouseOver(index + 1)}
                    />
                  );
                })}
              </div>
              <div>
                <input
                  type="text"
                  placeholder="input your name"
                  required
                  style={styles.input}
                  value={review.Name}
                  onChange={(e) => setReview({ ...review, Name: e.target.value })}
                />
              </div>
     
              <textarea
                placeholder="what's your feedback"
                required
                style={styles.textarea}
                value={review.review}
                onChange={(e) => setReview({ ...review, review: e.target.value })}
              />
              <button
                type="submit"
                style={styles.button}
                class="btn btn-primary"
                onClick={createReview}
              >
                submit
              </button>
            </div>
          </form>
     
          <section id="reviews">
            <div class="reviews-heading">
              <span>REVIEWS FROM CUSTOMERS</span>
            </div>
     
            <div className="container">
              <div className="row">
                {reviews.map((review, i) => ( // calling the api
                  <div className="col-md-6">
                    <div class="reviews-box">
                      <div class="box-top">
                        <div class="profile">
                          <div key={i}></div>
                          <div class="name-user">
                            <strong>{review.Name}</strong>
                          </div>
                        </div>
     
                        <div style={styles.stars}>
                          {Array.from({ length: review.Rating }).map((i) => (
                            <FaStar key={i} size={18} color={colors.orange} />
                          ))}
                        </div>
                      </div>
     
                      <div class="client-comment">{review.review}</div>
                    </div>
                  </div>
                ))}
              </div>
            </div>
          </section>
        </>
      );
    }
     
    const styles = {
      container: {
        align: "center",
        display: "flex",
        flexDirection: "column",
        alignItems: "center",
        boxShadow: "0 0 20px 0 #999",
        width: "30%",
        margin: "50px auto",
        flexDirection: "column",
      },
      input: {
        borderRaduis: 5,
        width: 300,
        margin: "10px 0",
        marginDown: "15px",
        minHeight: 30,
        padding: 1,
        height: "20px",
      },
      textarea: {
        border: "1px solid #a9a9a9",
        borderRaduis: 5,
        width: 300,
        margin: "20px 0",
        minHeight: 100,
        padding: 10,
      },
     
      button: {
        border: "1px solid #a9a9a9",
        borderRaduis: 5,
        width: 300,
        padding: 10,
        margin: "20px 0",
      },
    };
    export default App;
```

Here’s also a link to the full source code on [github.](https://github.com/oyedeletemitope/-Build-a-rating-app-with-react-and-strapi)

## Conclusion

We learned about contents types and how to build a rating app using Strapi as our backend. We created content, fed them to our website through Strapi's API. We also learned how to create reviews and feed them (insert) into our database. 

The truth is there are countless things we can use Strapi for, and this is just one of them.