MERN Stack for experience developers -Part 2
Published: 2021-09-19 10:51:43

If you haven't read first part of this article, read [here](https://dev.to/jitangupta/mern-stack-for-experience-developers-2nlj)

In this article we will continue setting up our client-side application.
### ReactJS setup
Let's create the React app.
We are again going to use node command line tool for that
```js
npx create-react-app frontend
```
_**Note**: if create-react-app package is not available, it may prompt you to install it._
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4xrohomgo6igq3kiutzf.png)
### Bootstrap
We are going to use bootstrap to design the frontend application.
Learn more [here](https://getbootstrap.com/).
```js
npm i bootstrap
```
Let's import the bootstrap design into `app.js` file and do some basic changes.
```jsx
import React, { Component } from 'react';
import "bootstrap/dist/css/bootstrap.min.css";
import './App.css';

class App extends Component{
  render(){
    return (
      <div className="container">
        MERN-Stack Todo App
      </div>
    );
  }
}

export default App;
```
If you will run the application, you can see something like below in your browser.
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1o2qvu5dprvqe93b6j96.png)
 
#### Add routing (React-Router-DOM)
Using `react-router-dom` we can add routing (multiple pages) into our application.
```js
npm i react-router-dom
```
Before defining routes, let's create few components first, which we will use to define the pages (routes) in our application. Create `create-todo.component.js`, `edit-todo.component.js` and `todos-list.component.js` into a components folder.
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1s8tf55slq1tr5ot826u.png)
After adding the above files, add some sample codes as follows
```jsx
// creat-todo.component.js
import { Component } from "react";

export default class CreateTodo extends Component{
    render(){
        return(
            <div>Hi From Create todo</div>
        )
    }
}

// edit-todo.component.js
import { Component } from "react";

export default class EditTodo extends Component{
    render(){
        return(
            <div>Hi From Edit todo</div>
        )
    }
}

// todos-list.component.js
import { Component } from "react";

export default class TodosList extends Component {
  render() {
    return <div>Hi From todos list</div>;
  }
}
```
Let's add the routing into our `App.js` file now
```jsx
// importing react & react-router-dom packages
import { Component } from "react";
import { BrowserRouter as Router, Route, Link } from "react-router-dom";

// importing components
import CreateTodo from "./components/create-todo.component";
import TodosList from "./components/todos-list.component";
import EditTodo from "./components/edit-todo.component";

// importing bootstrap & custom css
import "bootstrap/dist/css/bootstrap.min.css";
import "./App.css";


class App extends Component {
  render() {
    return (
      <Router> 
        <nav className="navbar navbar-expand-lg navbar-light bg-light">
          <div className="container">
            <Link to="/" className="navbar-brand">
              MERN Stack Demo
            </Link>
            <div className="collapse navbar-collapse" id="navbarSupportedContent">
              <ul className="navbar-nav me-auto mb-2 mb-lg-0">
                <li className="nav-item">
                  <Link to="/" className="nav-link">
                    Todos
                  </Link>
                </li>
                <li className="nav-item">
                  <Link to="/create" className="nav-link">
                    Add
                  </Link>
                </li>
              </ul>
            </div>
          </div>
        </nav>
        <div className="container">
          <Route path="/" exact component={TodosList} />
          <Route path="/edit/:id" component={EditTodo} />
          <Route path="/create" component={CreateTodo} />
        </div>
      </Router>
    );
  }
}

export default App;
```
Let's break above code down:
**BrowserRouter** is a router implementation that uses HTML history API to keep UI in sync with URL.
**Link** is used to define anchor tags and `to` is similar to `href`.
**Route**: As you can see, it has few properties like `path` defines the route & component defines which `component` to use if the path matches. `exact` tells that the path should be `/`, not `/xyz` or `/abc`. 
_**Note**: To read the parameter passed in the URL like `/edit/1`, we can use `this.props.match.params.id`. And while defining such routes, we use `/:id`._

Let's run the application and see what we have so far
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vg1mpww33cl4uevbvhvx.png)
So far, we have added routes and basic components. It's time to design the list component and bind data from server.

#### Add Axios
Using `axios` library we can make HTTP requests such as `GET`, `PUT`, `POST`.
```js
npm i axios
```
Now we are ready to design our todo list
```jsx
// importing packages
import { Component } from "react";
import { Link } from "react-router-dom";
import axios from "axios";

// functional component
const Todo = (props) => (    
  <tr>
    <td className={props.todo.completed ? 'completed' : ''}>{props.todo.title}</td>
    <td className={props.todo.completed ? 'completed' : ''}>{props.todo.description}</td>
    <td className={props.todo.completed ? 'completed' : ''}>{props.todo.priority}</td>
    <td>
      <span className={props.todo.completed ? 'd-none' : ''}><button type="button" onClick={() => props.finished(props.todo)} className="btn btn-primary btn-sm mx-1">Finish</button></span>
      <Link className="btn btn-sm btn-secondary" to={"/edit/" + props.todo._id}>Edit</Link>
    </td>
  </tr>
);

// class component
export default class TodosList extends Component {
  constructor(props) {
    super(props);
    // defining the state of the component
    this.state = { todos: [] };
 
    // this is required for event binding in react
    this.finishTask = this.finishTask.bind(this);
  }  

  // react life cycle method
  componentDidMount() {
    axios
      .get("http://localhost:4000/todos/") // consuming the get api
      .then((res) => {
        this.setState({ todos: res.data }); // data binding
      })
      .catch((error) => {
        console.log(error);
      });
  }

  // finish task event from table, 
  // Please note, we are making a PUT request to server 
  // to update the status of task
  finishTask(task){
    task.completed = true;
    axios
      .put("http://localhost:4000/todos/" + task._id, task)
      .then((res) => {
        if (res.status === 200) { // checking if the response is ok or not, status code 200 is for ok
          this.props.history.push("/"); // refreshing the page, please don't do this in production level application
        }
      });
  }

  // mapping the todo list
  todoList() {
    return this.state.todos.map((todo, index) => {
      return <Todo todo={todo} key={index} finished={(task) => this.finishTask(task)} />;
    });
  }

  // rendering the output
  render() {
    return (
      <div>
       <h4>Todo List</h4>
       <table className="table">
           <thead>
               <tr>
                   <th>Title</th>
                   <th>Description</th>
                   <th>Priority</th>
                   <th></th>
               </tr>
           </thead>
           <tbody>
           { this.todoList() }
           </tbody>
       </table>
      </div>
    );
  }
}

```
**Functional Component** is a JavaScript function that returns some JSX. It does not need to extend anything. And to read data in functional component, we use `props`.
**componentDidMount()** is a life cycle method form react which run after the component output has been rendered into DOM.

**Note:** 
1. As you can see, I am consuming APIs in same file, I am doing it to remove additional complications from this demo app.
2. Don't forget to read the additional comments written in above code file.

Before running your application, let's add some design for our completed task.
```css
.completed {
  text-decoration: line-through;
}
```
If you will run the application now, you will see something like below
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vgfzbeoitf86ohci2pgh.png)
_**Note**: As you can see I am already having few todos, I have created these todos using Postman, as shown in previous article._

Now, If will click on finish button, you can see the todo item has been marked as complete.
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/z16dddf812mad8z68m03.png)
 

_**Pro Tip**: If you are facing any kind of error and want to debug your code, (a) Open developer tools (ctrl+F12), (b) In source panel search(ctrl+P) for your todo-list.component, (c) add the debugger point on desired line number, and (d) Click on finish button in browser. You will see something like below_
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8cf1vkqdhwiy3q6zlhur.png)
 
Moving ahead, let's design the edit page now
```jsx
// importing packages
import React, { Component } from "react";
import axios from "axios";

// creating edit todo component
export default class EditTodo extends Component {
  constructor(props) {
    super(props);

    // defining state of the data
    this.state = {
      description: "",
      title: "",
      priority: "",
      completed: false,
      message: "",
    };

    // binding click events
    this.handleInputChange = this.handleInputChange.bind(this);
    this.onSubmit = this.onSubmit.bind(this);
  }

  // fetching the data from server
  componentDidMount() {
    axios
      .get("http://localhost:4000/todos/" + this.props.match.params.id)
      .then((response) => {
        // binding the data into current state
        // the bound data will reflect in page
        this.setState({
          description: response.data.description,
          title: response.data.title,
          priority: response.data.priority,
          completed: response.data.completed,
        });
      })
      .catch(function (error) {
        console.log(error);
      });
  }

  // updating the updated value into current state
  // In HTML, 'name' holds the key defined in above state
  // using which, we are updating the data below
  handleInputChange(event) {
    const target = event.target;
    const value = target.type === "checkbox" ? target.checked : target.value;
    this.setState({ [target.name]: value });
  }

  // Updating the data
  onSubmit(e) {
    e.preventDefault();
    const obj = {
      description: this.state.description,
      title: this.state.title,
      priority: this.state.priority,
      completed: this.state.completed,
    };
    axios
      .put("http://localhost:4000/todos/" + this.props.match.params.id, obj)
      .then((res) => {
        if (res.status === 200) {
          this.props.history.push("/"); // after successful update, redirecting to list page
        }
      });
  }

  render() {
    return (
      <div>
        <h3>Update Todo</h3>
        <form onSubmit={this.onSubmit}>
          <div className="form-group">
            <label>title: </label>
            <input
              type="text"
              name="title"
              className="form-control"
              value={this.state.title}
              onChange={this.handleInputChange}
            />
          </div>
          <div className="form-group">
            <label>Description: </label>
            <textarea
              type="text"
              name="description"
              className="form-control"
              rows="3"
              value={this.state.description}
              onChange={this.handleInputChange}
            ></textarea>
          </div>
          <div className="form-group">
            <div className="form-check form-check-inline">
              <input
                className="form-check-input"
                type="radio"
                name="priority"
                id="priorityLow"
                value="Low"
                checked={this.state.priority === "Low"}
                onChange={this.handleInputChange}
              />
              <label className="form-check-label">Low</label>
            </div>
            <div className="form-check form-check-inline">
              <input
                className="form-check-input"
                type="radio"
                name="priority"
                id="priorityMedium"
                value="Medium"
                checked={this.state.priority === "Medium"}
                onChange={this.handleInputChange}
              />
              <label className="form-check-label">Medium</label>
            </div>
            <div className="form-check form-check-inline">
              <input
                className="form-check-input"
                type="radio"
                name="priority"
                id="priorityHigh"
                value="High"
                checked={this.state.priority === "High"}
                onChange={this.handleInputChange}
              />
              <label className="form-check-label">High</label>
            </div>
          </div>
          <div className="form-check">
            <input
              className="form-check-input"
              id="completedCheckbox"
              type="checkbox"
              name="completed"
              onChange={this.handleInputChange}
              checked={this.state.completed}
              value={this.state.completed}
            />
            <label className="form-check-label" htmlFor="completedCheckbox">
              Completed
            </label>
          </div>

          <br />

          <div className="form-group">
            <input
              type="submit"
              value="Update Todo"
              className="btn btn-primary"
            />
          </div>
        </form>
      </div>
    );
  }
}
```
Let's break few important attributes of HTML code:
1. `name="priority"` key defined in state
2. `value="High"` HTML element holding the value.
3. `checked={this.state.priority === "High"}` current state of HTML element.
4. `onChange={this.handleInputChange}` event to be triggerd on `check`/`uncheck` event.

Let's edit some todo now
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ihwqj4mea7rq2k1tipbz.png)
As you can see the data has been updated successfully. And page has been redirect to list again. 
_**Note**: I have not added any screen-shot after redirection to make sure you are following along, please confirm by yourself._

Now only create todo task is pending, let's do that now
```jsx
// importing packages
import React, { Component } from "react";
import axios from "axios";

// create todo component
export default class CreateTodo extends Component {
  constructor(props) {
    super(props);

    this.state = {
      description: "",
      title: "",
      priority: "",
      completed: false,
      message: "",
    };

    this.handleInputChange = this.handleInputChange.bind(this);
    this.onSubmit = this.onSubmit.bind(this);
  }

  handleInputChange(event) {
    const target = event.target;
    const value = target.type === "checkbox" ? target.checked : target.value;
    this.setState({ [target.name]: value });
  }

  onSubmit(e) {
    e.preventDefault();
    const newTodo = {
      description: this.state.description,
      title: this.state.title,
      priority: this.state.priority,
      completed: this.state.completed,
    };
    axios.post("http://localhost:4000/todos/", newTodo).then((res) => {
      // after adding todo successfully, clearing the current state & showing success message
      if (res.status === 200) {
        this.setState({
          description: "",
          title: "",
          priority: "",
          message: "Todo created successfully.", 
        });
      }
    });
  }

  render() {
    return (
      <div style={{ marginTop: 10 }}>
        <h3>Create New Todo</h3>
        <form onSubmit={this.onSubmit}>
          <div className="form-group">
            <label>Title: </label>
            <input
              type="text"
              className="form-control"
              name="title"
              value={this.state.title}
              onChange={this.handleInputChange}
            />
          </div>
          <div className="form-group">
            <label>Description: </label>
            <textarea
              type="text"
              className="form-control"
              name="description"
              rows="3"
              value={this.state.description}
              onChange={this.handleInputChange}
            ></textarea>
          </div>
          <div className="form-group">
            <div className="form-check form-check-inline">
              <label className="form-check-label">
                <input
                  className="form-check-input"
                  type="radio"
                  name="priority"
                  id="priorityLow"
                  value="Low"
                  checked={this.state.priority === "Low"}
                  onChange={this.handleInputChange}
                />
                Low
              </label>
            </div>
            <div className="form-check form-check-inline">
              <label className="form-check-label">
                Medium
                <input
                  className="form-check-input"
                  type="radio"
                  name="priority"
                  id="priorityMedium"
                  value="Medium"
                  checked={this.state.priority === "Medium"}
                  onChange={this.handleInputChange}
                />
              </label>
            </div>
            <div className="form-check form-check-inline">
              <label className="form-check-label">
                <input
                  className="form-check-input"
                  type="radio"
                  name="priority"
                  id="priorityHigh"
                  value="High"
                  checked={this.state.priority === "High"}
                  onChange={this.handleInputChange}
                />
                High
              </label>
            </div>
          </div>
          <p>{this.state.message}</p>
          <div className="form-group">
            <input
              type="submit"
              value="Create Todo"
              className="btn btn-primary"
            />
          </div>
        </form>
      </div>
    );
  }
}
```
Let's run the application and create some todos, click on add from navbar & you will see a page like below, add some information & click on **create todo**
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/69zrfxli3akkkywp99u1.png)
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s7aaevaqh3z7sc323lc2.png)
Finally, we have completed the code for our todo application.
![yay](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xuszhn70kcimek1fs7gx.gif)
 
Few points before wrapping up this article...

### Error
_**Cannot read property of undefined**, after clicking finish todo button_
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/azojh4zxk048r449869v.png)
This error is occurring because `this` context is not available in current scope. To resolve this change the `function` to `arrow function`. In our demo above, array function has been used.
```javascript
return this.state.todos.map((todo, index) =>{
      return <Todo todo={todo} key={index} finished={(task) => this.finishTask(task)} />;
    });
```
below code breaks
```javascript
return this.state.todos.map(function(todo, index) { // this breaks
      return <Todo todo={todo} key={index} finished={(task) => this.finishTask(task)} />;
    });
```

### Points to keep in mind
1. Source code of the article can be found [here](https://github.com/learn-code-share/mern-stack)
2. For debugging your node app, follow YouTube [video](https://www.youtube.com/watch?v=2oFKNL7vYV8)
3. You may have noticed that I have used a single repository to manage both of my applications. It is just for this demo. Here is my workspace, and how I am running both applications parallelly.![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5569n1bv7clbbveg1kon.png)