# Build a MySQL Node.js CRUD App #3: The Client-Side with React

Hello and welcome to the 3rd part of [Let's Build a MySQL Node.js CRUD App series](https://hashnode.com/series/lets-build-a-mysql-nodejs-crud-app-ckhzrl98g022j99s11xymfqkn)! In the previous article, we have implemented all our GET, POST, PUT and DELETE routes in our server.

> If you haven't read the previous article, please find it [here](https://lo-victoria.com/build-a-mysql-nodejs-crud-app-2-mysql-integration).

In this part, we will be working on our front-end with React to complete our MySQL CRUD app!

## Step 1: Install npm packages
Install axios and cors to allow our app to make requests to the server. Install react-hook-form for easy form handling in React.
```
npm install axios cors react-hook-form
```
## Step 2: Import cors
In `server.js`, include the import statement at the top to use cors.
```
const cors = require("cors");
```
Then, to use it, add this line below the `const app` line.
```
app.use(cors());
```
This will allow our client-side at `localhost:3001` to be able to make requests to the server at port `3000`. To understand more about CORS, feel free to read this article on  [Introduction to Cross-Origin Resource Sharing](https://lo-victoria.com/introduction-to-cross-origin-resource-sharing-cors).

## Step 3: Read Reviews
In `App.js`, we want to get and display the reviews from MySQL for users to read. To do so, we first import the following:
```
import { useState, useEffect } from "react";
import axios from "axios";
```
Next, our code will proceed as:
1. Initialize an array called `reviews`, which contains all review data
2. Create function to GET all the reviews from server store to `reviews` array.
3. Create a `useEffect` hook to update `reviews` 

```
// 1.
const [reviews, setReviews] = useState([]);
// 2.
const getReviews = () => {
    axios.get("http://localhost:3000/reviews").then((res) => {
      setReviews(res.data);
    });
};
// 3.
useEffect(() => {
    getReviews();
}, [reviews]);
```
Lastly, to display the data in `reviews`, we use `map()` in the return function and envelop it with a `<div className="reviews">` as shown:
```
<div className="reviews">
{reviews.map((item) => {
    return (
       <div className="review">
          <h3>Title: {item.book_title}</h3>
          <h3>Review: {item.book_review}</h3>
          <h3>Rating: {item.book_rating}</h3>
       </div>
    );
})}
</div>
``` 
Then run the server with `nodemon server.js` and start the React app with `npm start`.

Our app should display data from our database immediately after launching.

![read.PNG](https://cdn.hashnode.com/res/hashnode/image/upload/v1607023746739/vRF-fzFrd.png)

## Step 3: Create Reviews
Now let's create the components for our React app to perform the Create operation to our database.

Create a file called `Add.js`, which will be the component that allows the user to create and add a new book review into the database by submitting a form using `react-hook-form` and `axios`. 

In this file, add the following import statements at the top.
```
import { useForm } from "react-hook-form";
import axios from "axios";
```
Then, we will code the following:
1. Initialize form using `useForm`
2. Create an onSubmit handler function that will insert the submitted form data into the database.
3. Update the reviews array in App.js

```
export default function Add(props) {
  // 1.
  const { register, handleSubmit } = useForm();
  // 2.
  const onSubmit = (data) => {
    console.log(data);
    addReview(data);
  };
  
  // function to make a POST req to the server to insert data to MySQL db
  const addReview = (data) => {
    axios.post("http://localhost:3000/reviews", data).then(() => {
      // 4.
      props.setReviews([...props.reviews, {data}]);
    });
  };
}
```
And then, create the appropriate HTML form in the return function like the example below:
![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1606683812644/NHBrT_24w.png)

Import this component into `App.js` and include it like so:
```
<Add reviews={reviews} setReviews={setReviews} />
```

## Step 4: Update Reviews
We are now able to Create and Read from our MySQL database. Let's work on the Update next.

Create a `Edit.js` file, a component that returns a form which a user can submit to update values of a specific review data.

To allow the user to update an existing review, we will:
1. Import the necessary packages to `Edit.js`
2. Initialize our React form
3. Create a function to update our database when the form is submitted
4. Update our `reviews` array

```
// 1.
import { useForm } from "react-hook-form";
import axios from "axios";

export default function Edit(props) {
  // 2.
  const { register, handleSubmit } = useForm();
 
  // 3.
  const onSubmit = (data) => {
    console.log(data); //{book_review: ..., book_rating: ...}
    data["id"] = props.id; //add the id from props
    updateReview(data);
  };

// This will update existing data with new submitted values
const updateReview = (data) => {
    axios.put("http://localhost:3000/reviews", data).then((res) => {
      // 4.
      props.setReviews(
        props.reviews.map((item) => {
          return item.id === props.id? {
                id: item.id,
                book_title: item.book_title,
                book_review: item.book_review,
                book_rating: item.book_rating,
              }
            : item;
        })
      );
    });
  };
```
Then, create a simple form in the return function and add the `Edit` component in `App.js`.

Add it inside our `<div className="reviews">` and remember to pass in `id` as `item.id` as attributes from our Edit component to work.
```
<div className="reviews">
        {reviews.map((item) => {
          return (
            <div className="review">
              <h3>Title: {item.book_title}</h3>
              <h3>Review: {item.book_review}</h3>
              <h3>Rating: {item.book_rating}</h3>
              {/*Add Edit here*/}
              <Edit id={item.id} reviews={reviews} setReviews={setReviews} />
            </div>
          );
        })}
</div>
```
The result will look like this.

![edit.PNG](https://cdn.hashnode.com/res/hashnode/image/upload/v1607024858244/xKaCBJc2K.png)

## Step 5: Delete Reviews
Finally, our Delete operation will be the simplest of all. Our client just needs to provide the `id` of the review to delete from the database.

The request URL will contain the `id` as params like: `http://localhost:3000/:id`

So to do this, create a `Delete.js` file and proceed as follows:
1. Import axios
2. Create function to delete a review where `:id` in the URL is `props.id`
3. Update reviews array
4. Create the delete button in return

```
// 1.
import axios from "axios";
export default function Delete(props) {
  // 2.
  const deleteReview = () => {
    axios.delete(`http://localhost:3000/reviews/${props.id}`).then((res) => {
      // 3.
      props.setReviews(props.reviews.filter((item) => {
          return item.id !== props.id;
        })
      );
    });
  };

// 4.
return (
    <button className="del-btn" onClick={deleteReview}>
      Delete Review
    </button>
  );
}
```
As usual, import this component to `App.js` and insert it below our Edit component. Remember to include the relevant attributes to pass as props for Delete to work.
```
<div className="review">
    <h3>Title: {item.book_title}</h3>
     <h3>Review: {item.book_review}</h3>
     <h3>Rating: {item.book_rating}</h3>
     <Edit id={item.id} reviews={reviews} setReviews={setReviews} />
      {/*Add Delete here*/}
     <Delete id={item.id} reviews={reviews} setReviews={setReviews} />
</div>
```
### Final result
And now, we should have a simple React app that performs the CRUD operations with our MySQL database!

![yay.gif](https://cdn.hashnode.com/res/hashnode/image/upload/v1607026169943/PK0gkRoN0.gif)

Thanks for reading! We have finally completed our app but what's next? It's deploying it! In the next part of this series, let's learn how to deploy our full-stack React app to Heroku. 

If this series has been helpful so far, do give this article a like or share and stay tuned for the next one. Cheers!

-----
## Resources Used
- [axios](https://www.npmjs.com/package/axios)
- [cors](https://www.npmjs.com/package/cors)

