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:
- An introduction to JSX
- Choosing Sides: Functional vs. Class Components
- Props vs. State: Understanding React's Data Handling
- Go to the section on 'Creating a Simple Note-taking App with CRUD Operations'
- 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.
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.
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".
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.
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.
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.
Step 2: Update App.js the reflect the correct name of FunctionHello. Also, give it a name="John"
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;
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
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.
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;
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;
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;
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
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:
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
Post a Comment