Refactoring the Pro MERN App

Bertill Browne
The Startup
Published in
4 min readMay 23, 2020

--

Chater 4 — React State

Photo by Tudor Baciu on Unsplash

Pro MERN Stack is a book that gives step by step instructions on building a CRUD-based Issue Tracker application. In a previous article, I explained the first steps that I took to refactor the code in the third chapter to allow the use of Hooks.

First, I replaced the class declaration syntax of each of these components with the ES6 arrow function declaration, with “props” as an argument and “const” in front. Then I removed the “render()” method. Finally, I removed the “this” keyword from in front of the “props” in the child components.

In this article, I will explain what I did for the fourth chapter — React State.

Notice that the React and React-Dom libraries are imported, from a CDN, into the app. This is in the index.html file via the script tag. Notice also, that version 15.2.1 is being used. This version is before Hooks were introduced. It had to be refactored to version 16.8 or later, to use Hooks. The original code:

<scriptsrc=“https://cdnjs.cloudflare.com/ajax/libs/react/15.2.1/react.js</script><script src=“https://cdnjs.cloudflare.com/ajax/libs/react/15.2.1/react-dom.js"></script>

was refactored as:

<script src=”https://unpkg.com/react@16.13.0/umd/react.production.min.js </script><script src=”https://unpkg.com/react-dom@16.13.0/umd/react-dom.production.min.js"></script>

Since React is imported from a CDN into the browser and exposed to the windows object as React, I accessed the Hooks useState and useEffect by destructuring them from React, at the top of the app.jsx file as shown below.

const { useState, useEffect } = React

Next, I replace the setState() method in the constructor of the IssueList component with the useState hook. thus

this.state = {issues: issues};

became

const [newIssues, setNewIssues] = useState(issues);

The timer function in IssueList as shown below

setTimeout(this.createTestIssue.bind(this), 2000);

was refactored and placed in a useEffect hook. The useEffect hook performs side effects in functional components. It replaces several lifecycle methods in class components, such as componentDidMount, componentDidUpdate and componentWillUnmount.

Since the useEffect function is an arrow function there is no need to bind the timer function. The bind(this) functions was, therefore, removed as shown below.

useEffect(() => {const timer = setTimeout(createTestIssue, 2000);}, []);

The “createIssue()” function was refactored as an arrow function as explained in the previous post. The code to copy the existing issues array using the “array.slice()” method was removed and “this.state” was removed from in front the code to generate the “id” for the “newIssue” object. Thus

newIssue.id = this.state.issues.length + 1;

became

newIssue.id = newIssues.length + 1;

The “setState” function was replaced by “setNewIssues” function from the “useState” hook. It destructures the existing “issues” array and adds the new issue. thus

newIssues.push(newIssue);this.setState({ issues: newIssues });

became

setNewIssues(prevIssues => […prevIssues, newIssue]);

The refactored code is shown below.

const createIssue = (newIssue) => {newIssue.id = newIssues.length + 1;setNewIssues(prevIssues => […prevIssues, newIssue]);}

The “createTestIssue()” function was refactored as an arrow function and the “render()” function was removed as explained in the previous post.

The useState hook declaration was changed from

this.state = { issues: [] };

to

const [newIssues, setNewIssues] = useState([]);

The loadData() function was refactored as shown below.

const loadData = () => {setNewIssues(prevIssues => […prevIssues, …issues]);}

The loadData() function was added to the useEffect function and called in a setTimeout() function. This is shown below.

useEffect(() => {const data = setTimeout(loadData, 500);const issue1 = setTimeout(createTestIssue, 2000);}, []);

The “this” keyword was removed from in front of the createTestIssue in the onClick event in the button. so this

<button onClick={this.createTestIssue}>Add</button>

became this

<button onClick={createTestIssue}>Add</button>

Communicating from Child to Parent

In Listing 4.4 the component was rewritten as a functional component. The constructor was removed, the “this” keyword was removed from in front of the “createIssue()” and the “handleSubmit()” functions and the “render()” function was removed. Thus,

class IssueAdd extends React.Component {constructor() {super();this.handleSubmit = this.handleSubmit.bind(this);}handleSubmit(e) {/*
*
*
*/
this.props.createIssue({/*
**
*/
}render() {return (<div><form name=”issueAdd” onSubmit={this.handleSubmit}>/*
*
*
*/
</div>)}}

Became

const IssueAdd = props => {const handleSubmit = e => {/*
*
*
*/
props.createIssue({/*
*
*
*/
});// clear the form for the next inputform.owner.value = “”;form.title.value = “”;}return (<div><form name=”issueAdd” onSubmit = {handleSubmit}>/*
*
*
*/
</div>);}

If you find this article helpful, you can buy me a coffee to show your appreciation.

--

--