Blog Post 2: Diving Deeper into ReactJS - Bridging Theory with Practice

Estimated Reading Time: 20-25 minutes.

Hello there, fellow coders!

Welcome back to my ReactJS journey. If you haven't read my first blog post yet, where we explored of ReactJS, feel free to check it out here: Discovering ReactJS. If you are unfamiliar with React or JavaScript, I recommend brushing up on ES6 syntax, especially topics like let and const, arrow functions, and imports and exports.

First and foremost, thank you for your feedback on my first blog post. I appreciate it, and it fuels me to create more valuable content for you!

In this second installment, we will delve deeper into the heart of ReactJS. Let's learn some new features in React and make a practical demonstration.

Here's what you can expect from today's blog:

  1. An introduction to JSX
  2. Choosing Sides: Functional vs. Class Components
  3. Props vs. State: Understanding React's Data Handling
  4. Go to the section on 'Creating a Simple Note-taking App with CRUD Operations'
  5. Directly access the 'CRUD Application Section with React'

To ensure you understand the new concepts and have a small project to take away, we will build a functional note-taking application together. For those who learn best by seeing things in action, I've included a video demonstration of the process. And don't worry, for those who prefer text over videos, I've got you covered with a detailed explanation and GitHub code below.

So, ready to deepen your ReactJS skills? Let's dive right in!

1. JSX:

a. What is JSX?

JSX (JavaScript XML) is a syntax extension for Javascript. It allows you to write HTML-like code in your React components, which React then transpiles into standard JavaScript understood by the browser.

There are two important rules for JSX:

  • Use CamelCase for classNames, e.g., 'myClassName' instead of 'my-class-name'.
  • Always close your tags.
  • If the tag doesn't have a matching closing tag, you can self-close it, e.g., <img />.

b. The Benefits: Why should we use it?

JSX brings a significant benefit to the developers: it makes our code cleaner and more readable. For example, consider our 'HelloWorld' project from the first blog. If we take the App.js file and run it through Babel (a JavaScript compiler), we can see what the browser reads and interprets.


Figure 1 - Babel demonstration.

As you can observe, the output code becomes more complex than the original JSX code. While it is not mandatory to use JSX in React, its ability to maintain simplicity in the face of complex functionality makes it a popular choice among developers, compared to Vanilla JavaScript and other alternatives.

2. Functional Components vs. Class Components:

a. Defining the Terms: What are Functional and Class Components?

In my blog 1, I briefly mentioned that the declarative and component-based are the big advantage of ReactJS. Today, we will dig a bit deeper into the concepts of Functional and Class components.

Components in React are quite like methods in Java. They are self-contained pieces of code that manage their state and render UI, and they are the building blocks of any React app.

i. Functional components are JavaScript functions that accept props (definition in next session) as an argument and return a React element. They are called "functional" because they are just functions. You can declare them outside or inside of other components and then export and import them where needed.

ii. Class component is ES6 classes that extend from React.Component. They provide more features (like lifecycle methods) out of the box. Like functional components, you declare these components and make sure they're imported and exported correctly where needed.

b. Choosing the Right Components

Both functional and class components can coexist in a React application, and understanding when to use each is a key aspect of mastering ReactJS.

Functional component Class Components
Nature Simple functions. ES6 classes must extend from ‘React.Component’.
Usage Preferred to use in most cases due to the simplicity and ease of use. Used for more complex UI logic or when lifecycle methods are needed
State Handling Stateless: use mostly for components that don’t need to have and maintain state. Stateful: maintains their own private data (‘state’) and contain logic for state updates
When to Use Whenever possible especially for simpler, stateless UI components Use to handle complex logic or manage state.

c. Codes:

Let's investigate the details of functional and class components in React by rendering some simple JSX on the screen.

Functional Component:

Step 1: Create a new folder called "component" under the "src" directory and create a new JavaScript file named "FunctionHello.js". For simplicity, we will use the "export default" syntax. This works similarly to class components — we need to export the function so that our main "App.js" component can import it and render the output properly.

Figure 2 - Functional component class

Step 2: Inside the return statement of "App.js", comment out the part we implemented in the previous blog post. Now, call the "FunctionHello" function within the return statement. Remember to include your component in JSX by using its tag, like so: <FunctionHello />. Also, remember to close the tag, which can be done inline for components without children, as shown. It's also necessary to import the functional component at the top of "App.js".

Figure 3 - App.js and browser display

Class Component Codes:

Step 1: Create a JavaScript file named "ClassHello.js" inside the "component" folder. Be sure to extend React.Component right after the mandatory line import React from 'react'. It's also necessary to include export default ClassHello at the end of the file so that "App.js" can import it and render the output properly.

Figure 4 - Class Component - ClassHello

Step 2: Similarly to the functional component, you need to import "ClassHello" at the top of "App.js". Then, include <ClassHello /> in your JSX within the return statement using a self-closing tag.

Figure 5 - App.js and its output for class component

3. Props vs. State

a. What are Props and States?

Props

Props (short for properties) in React are a way to pass data from a parent component to its child components. They're like parameters in a function and serve to make our components more dynamic and reusable. Props are read-only, or in technical terms, they are immutable. It means that a component cannot change its props - they must always come from the parent.

State

State is like props in the sense that it holds data, but it's primarily used for data that will change over time and needs to be kept in sync with the UI. Unlike props, state is mutable and can be changed within the component using a special function called setState in class components or the useState hook in functional components.

When using props and state, you can decide whether to use one over the other based on the nature of the data and its handling requirements.

b. The Application: When should we use one over the other?

Props States
Nature Immutable (Read-only) Mutable (Can be changed)
Usage Pass data from parent to child components Hold data that might change, and the UI needed to be updated with that change
State Handling N/A Use ‘setState’ or ‘useState’ to modify
When to Use When the data will not change When you need to keep track of changing data

c. Breaking It Down: Code examples for a clear understanding.

Props:

Step 1: Let’s modify our class we created before to demostrate how is Props going to work.

Figure 6 - FunctionHello to demonstrate the State.

Step 2: Update App.js the reflect the correct name of FunctionHello. Also, give it a name="John"

Figure 7 - App.js and browsers displayed.

4. Practical Example: Creating a Simple Note-taking App with CRUD Operations

We will build a very simple Taking Note app with React. I will include my instructional video and github code at the end. However, I will walk you through my code first. In the first section, I will mainly focus on the displaying the task with the addItem only. You will see the editItem and deleteItem in the advance sections followed this. However, you can jump right into Jump to the CRUD Application Section

a. Overview of the To-Do List App:

Our To-Do List App will have two main components:

  • ToDoItem: This is a functional component that will receive the to-do item details via props and render them. These will be our child components.
  • ToDoList: This is a class component that will maintain the state of the to-do list and render the individual ToDoItem components. This will be our parent component.

Our Note-Taking app will also have a button to add new items to the list and an input field.

Detail codes and explanation for each class:

Now, let's take a look at a sample code for a ToDoList component to understand how to organize and structure our code:

1. ToDoItem.jsx


import React from 'react';
      
As always, we must import including ‘React’.

function ToDoItem(props) {
  return (
    <li>{props.item}</li>
  );
}
export default ToDoItem;
      
This functional component receives props as an argument and returns a list item containing props.item. props is an object containing properties passed down from the parent component. In this case, props.item is the individual to-do item. Finally, as always we need to export the name of this functional component.

2. ToDoList.jsx


import React from 'react';
import ToDoItem from './ToDoItem';
      
At the top of this jsx file: we include the import ‘React’ which must include for all the React components, and ‘ToDoItem’ component which we created in the previous step.

class ToDoList extends React.Component {
  constructor() {
    super();
    this.state = {
      items: [],
      currentItem: '',
    };
  }
      
Next, we define our ‘ToDoList’ class that extends ‘React.Component’ which means that this is a React Class component. The ‘constructor’ method here is to set up our initial state. In our state, it consists of an array of to-do items, and ‘currentItem’ is to track which item is currently being added.

handleChange = (event) => {
  this.setState({
    currentItem: event.target.value,
  });
}
addItem = () => {
  this.setState((prevState) => ({
    items: [...prevState.items, prevState.currentItem],
    currentItem: '',
  }));
}
      
The methods above handle the changes in the input field and to add items to the list. ‘handleChange’ updates the ‘currentItem’ in our state as the user types into the input field. ‘addItem’ adds the ‘currentItem’ to our ‘items’ arrays and resets ‘currentItem’ to an empty string when the “Add Item” button is clicked.

render() {
  return (
    <div>
      <h2>To-Do List</h2>
      <input type="text" value={this.state.currentItem} onChange={this.handleChange} />
      <button onClick={this.addItem}>Add Item</button>
      <ul>
        {this.state.items.map((item, index) => (
          <ToDoItem key={index} item={item} />
        ))}
      </ul>
    </div>
  );
}
}
      
The render method returns the JSX that will be displayed on the screen. This includes a title, an input field, a button, and a list of ToDoItem components. The value of our input field is set to this.state.currentItem, and the onChange event calls this.handleChange to update the currentItem as the user types. The "Add Item" button has an onClick event that calls this.addItem to add the current item to the list. The list of items is generated by mapping over this.state.items and creating a new ToDoItem for each item.

     export default ToDoList;
      
At the end of this component class, we need to export it, so we can use it in the App.jsx

3. App.jsx

This is the root component that includes our ‘ToDoList’ component.


import React from 'react';
import ToDoList from './ToDoList';
function App() {
  return (
    <div className="App">
      <ToDoList />
    </div>
  );
}
export default App;
      
Here we import React and our ToDoList component. The App component then returns a div that includes the ToDoList component.

D. Project Creation:

In this section, we'll go through the steps to create the project using Visual Studio Code as our Integrated Development Environment (IDE) and Node version 16.14.0. Please make sure you have these prerequisites installed. If not, you can refer to Blog 1: Setup Guide for IDE and Node Installation

Step 1: Create a new React application.

Launch Visual Studio Code and navigate to your preferred workspace. Open a terminal (Ctrl+ ) and execute the command: npx create-react-app to-do-list-demo`. This will create a new React application named 'to-do-list-demo'. The operation may take a few minutes depending on your machine's performance.


			npx create-react-app to-do-list-demo
            
Figure 8 - Create React Application

The processes will take a minute or two minutes depednding on how powerful your machine is you see Happy hacking at the end.

Step 2: Change to the application directory and start the React application.

Use the cd command to navigate into your new 'to-do-list-demo' directory. Then run npm start to launch the React application. Your application should now be running on your local host and you can view it in your browser.


		cd to-do-list-demo
	

		npm start
	

The right result shows the app successfully launch in local host on the browsers similar with the screenshot below.

Figure 9 - The terminal and browsers after you typed the commands

Step 3: Create a new JSX file named 'ToDoItem.jsx'.

Navigate to the 'src' directory in your React application and create a new JSX file named 'ToDoItem.jsx'. Then, insert the provided 'ToDoItem.jsx' code into this file.


	// ToDoItem.jsx
    import React from 'react';
    function ToDoItem(props) {
    return (
    <li>{props.item}</li>
  	);
	}
	export default ToDoItem;
	  
Figure 10 - ToDoItem.jsx

Step 4: Create another JSX file named 'ToDoList.jsx'.

In the 'src' directory, create another new JSX file named 'ToDoList.jsx'. Insert the provided 'ToDoList.jsx' code into this file.


      // ToDoList.jsx
import React from 'react';
import ToDoItem from './ToDoItem';

class ToDoList extends React.Component {
    constructor() {
      super();
      this.state = {
        items: [],
        currentItem: '',
      };
    }

    handleChange = (event) => {
        this.setState({
          currentItem: event.target.value,
        });
    }
      addItem = () => {
        this.setState((prevState) => ({
          items: [...prevState.items, prevState.currentItem],
          currentItem: '',
        }));
    }
    render() {
  return (
    <div>
      <h2>To-Do List</h2>
      <input type="text" value={this.state.currentItem} onChange={this.handleChange} />
      <button onClick={this.addItem}>Add Item</button>
      <ul>
        {this.state.items.map((item, index) => (
          <ToDoItem key={index} item={item} />
        ))}
      </ul>
    </div>
    );
	}
	}
      export default ToDoList;
        
Figure 11 - ToDoList.jsx

Step 5: Rename 'App.js' to 'App.jsx' and update its content.

Find the 'App.js' file in the 'src' directory and rename it to 'App.jsx'. Replace its content with the provided 'App.jsx' code.


        // App.jsx
        import React from 'react';
        import ToDoList from './ToDoList';
        function App() {
          return (
            <div className="App">
              <ToDoList />
            </div>
          );
        }
        export default App;
      
Figure 12 - App.jsx

Step 6: Verify your changes.

Go back to your browser where the React app is running. You should see the changes reflected immediately, demonstrating the powerful feature of hot-reloading in ReactJS. If your browser was closed, do not worry - just open a new terminal, ensure you are in the right directory, and start the React application again with npm start.


        npm start
  
Figure 13 - Browsers auto rendered
Figure 14 - Browser after adding items
This section is optional because it requires a bit more works than the previous step to be able to make it a CRUD - Create, Read, Update and Delete - Note-taking application!

Step 7: Update the ToDolist with updateItem and deleteItem. Also, handle it in the state.

If you skip directly to Step 7, keep in mind that the previous 6 steps covered essential information, such as displaying the items and the implementation of the addItems function along with its relevant code. For a comprehensive understanding, feel free to scroll up and review the provided details.

        
        // ToDoList.jsx
        // Add this method right below addItem method. 
        updateItem = (index, newItem) => {
            const { items } = this.state;
            let newItems = [...items];
            newItems[index] = newItem;
            this.setState({
              items: newItems,
            });
        }

        deleteItem = (index) => {
            const { items } = this.state;
            this.setState({
              items: items.filter((item, itemIndex) => itemIndex !== index),
            });
        }
        
        

Update the render part in ToDoList.jsx

        
        render() {
        return (
          <div>
            <h2>To-Do List</h2>
            <input type="text" value={this.state.currentItem} onChange={this.handleChange} />
            <button onClick={this.addItem}>Add Item</button>
            <ul>
              {this.state.items.map((item, index) => (
                <ToDoItem 
                  key={index} 
                  item={item} 
                  deleteItem={() => this.deleteItem(index)} 
                  updateItem={this.updateItem.bind(this, index)} 
                />
              ))}
            </ul>
          </div>
        );
        }
        
        

Step 8: Update the ToDoItem.jsx with new handleEdit, handleSave, and update the display form to handle necessary changes.

        
        // ToDoItem.jsx
        import React from 'react';

        class ToDoItem extends React.Component {
          constructor() {
            super();
            this.state = {
              isEditing: false,
              item: ''
            };
          }

          handleEdit = () => {
            this.setState({
              isEditing: true,
              item: this.props.item
            });
          }

          handleSave = () => {
            this.props.updateItem(this.state.item);
            this.setState({
              isEditing: false,
              item: ''
            });
          }

          handleChange = (event) => {
            this.setState({
              item: event.target.value,
            });
          }

          render() {
            return (
              <li>
                {this.state.isEditing ? 
                <div>
                  <input type="text" value={this.state.item} onChange={this.handleChange} />
                  <button onClick={this.handleSave}>Save</button>
                </div> 
                : 
                <div>
                    {this.props.item}
                 <button onClick={this.handleEdit}>Edit</button>
                <button onClick={this.props.deleteItem}>Delete</button>
                </div>
                }
              </li>
            );
          }
        }

        export default ToDoItem; 
        
        

Here is the fully updated ToDoItem.jsx


        
        // ToDoList.jsx
        import React from 'react';
        import ToDoItem from './ToDoItem';

        class ToDoList extends React.Component {
          constructor() {
            super();
            this.state = {
              items: [],
              currentItem: '',
            };
          }

          handleChange = (event) => {
            this.setState({
              currentItem: event.target.value,
            });
          }
          addItem = () => {
            this.setState((prevState) => ({
              items: [...prevState.items, prevState.currentItem],
              currentItem: '',
            }));
          }

          updateItem = (index, newItem) => {
            const { items } = this.state;
            let newItems = [...items];
            newItems[index] = newItem;
            this.setState({
              items: newItems,
            });
          }

          deleteItem = (index) => {
            const { items } = this.state;
            this.setState({
              items: items.filter((item, itemIndex) => itemIndex !== index),
            });
          }

          render() {
            return (
              <div>
                <h2>To-Do List</h2>
                <input type="text" value={this.state.currentItem} onChange={this.handleChange} />
                <button onClick={this.addItem}>Add Item</button>
                <ul>
                  {this.state.items.map((item, index) => (
                    <ToDoItem 
                      key={index} 
                      item={item} 
                      deleteItem={() => this.deleteItem(index)} 
                      updateItem={this.updateItem.bind(this, index)} 
                    />
                  ))}
                </ul>
              </div>
            );
          }
        }

        export default ToDoList;
        
        

Here is the final products:

Figure 15 - New button is added for Edit and Delete
Figure 16 - The assignment field is updated
Figure 17 - The edit value is updated
Note: In this demonstration, our To-Do List application does not include a database, meaning all tasks will disappear after refreshing the page. This simplicity allows us to focus on fundamental React application design. In real-world applications, however, you would typically incorporate a database to persistently store data across sessions and devices. Keep this in mind when considering how to build upon this project or apply these concepts elsewhere. Stay tuned for future posts where we will delve into database integration with React applications.

E: GitHub Repository

The source code for this demo can be accessed through its GitHub repository. You can find it at the following link: https://github.com/tam279/to-do-list-demo.git

In conclusion, I hope this blog post has helped you understand ReactJS better. We've learned a lot, from JSX to class and functional components, and from props and state to building a simple application with ReactJS.

Your journey in learning ReactJS does not stop here. The more you practice and build, the better you will become. Try making your own projects, maybe add delete or edit buttons to our simple note-taking application.

I'm really thankful for your support and feedback on this series. Remember, it's normal to find these ideas hard at first, I did too. We are all here to learn, improve, and help each other.

Thank you for being part of this journey into ReactJS. I'm excited to share more tips and insights with you in future posts. Keep coding, everyone!

Connect with me on LinkedIn at: www.linkedin.com/in/tamnguyen279

Comments

Popular posts from this blog

Blog Post 1: Disconvering ReactJS: Building Your First Application