Your First React App Using Hooks

Getting Started with ReactJS heyylateef | Sep 28 2022

Overview

Are you a beginner that wants to get into programming but don't know where to start? Or you know about programming but know that you for sure want to get into web development? Or are you a complete beginner that believes programming is all about manipulating zeroes and ones on a display like they display in 80s-90s Hollywood films? Well, you're looking at the right article! This article is catered to any who fits the following description:

  • Pure beginner; this is the first time you looked at any programming tutorial
  • I heard what HTML and/or JavaScript is

Programming is a large discipline, you can get into data engineering, web development, mobile application development, and much more. Here at LateefLab, (obviously) we're focused on web development. One of the most, if not, most popular things in web development is ReactJS.


What is React?

ReactJS is a front-end JavaScript library developed and maintained by Facebook. It utilizes a web page's "virtual DOM" to improve performance of your web application.  Typical use cases for ReactJS include:

  • Single Page Applications
  • Ecommerce websites
  • Front facing APIs

Installation (or just use your browser!)

You have two options on how you can use on your computer:

  1. Local Development on your computer
  2. Code directly in your browser

1. Local Development Setup (NodeJS and Text Editor/IDE)

First, install the latest LTS (long term support) version of NodeJS on your computer. Secondly, follow these steps to install Create-React-App on your computer. Create-React-App is a way to bootstrap your React environment with most of the necessary packages to get you using React quickly.


2. In Browser (using StackBlitz)

Thankfully with recent advancements in the web, you can follow along without leaving your browser! Below at the end of this tutorial, there is an embedded, interactive window that contains a copy of this project used in this tutorial. Feel free to use it, we placed it there for curious individuals like yourself so you can tinker and learn without leaving your web browser.


Setup 

For those doing local development (if you're using StackBlitz, you don't need to do this as the project was setup for you), open your cmd/terminal and do the following commands:

$ npx create-react-app react-hook-todo-tutorial

Open the folder titled react-hook-todo-tutorial in your text editor/IDE. You would see the following file structure:

    react-hook-todo-tutorial/
node_modules/
public/
src/
package-lock.json
package.json
README.md

Before we get started, lets install a npm package (Bootstrap) to improve our React project. NPM (Node Package Manager) is package manager for NodeJS, it is one of the supported package managers for React and often used to install/uninstall external packages in our projects. We'll use npm install Bootstrap so we can to add Bootstrap styling to our components. In your cmd/terminal, run the following command:

$ npm install bootstrap


In React, components are the building blocks of our application.Most React developers love to keep their folder structure as organized as possible. One popular way to keep our project organized is to make folders specifically for our components. Inside of your text editor/IDE, make a folder within the /src folder titled components

Your folder structure should look like this:

    react-hook-todo-tutorial/
node_modules/
public/
src/ components/
package-lock.json
package.json
README.md

Exploring index.js 

Nearly all we're focusing on in this tutorial is within the /src folder. However since we're using Bootstrap, we have to import the Bootstrap CSS. Within our project's root folder, open index.js. index.js is the entry point to our React application. You'll notice that the App component is already there within the ReactDOM.render() method. This means that when we startup our application, we're telling it to render the App component (and whatever else the App component is supposed to render). While inside index.js, add the following line to import Bootstrap CSS and save the file:

import "bootstrap/dist/css/bootstrap.min.css"; // Add this; Bootstrap CSS


Your entire index.js should look like the following:

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import "bootstrap/dist/css/bootstrap.min.css"; // Add this; Bootstrap CSS

ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();


Exploring App.js (Part 1)

Open the /src folder and take a look at App.js.  This is where we'll write the bulk of our application. We'll use React Hooks to control state of our components. React Hooks help us control the behavior of our component by using functions instead of classes. For more information on React Hooks, take a look at the official documentation

To get things started, import the React Hook useState at the top of the file:

import React, { useState } from 'react';

Since we're creating a simple todo list application, lets get started with some default todos so we can manipulate and harness the power of React (using Hooks)! Copy and paste the following snippet inside your function App():

function App() {
//creates a state variable ("todos") and a function to set the state ("setState").
//uses "useState" React Hook to define a state property named "text", along with its default value (for this example, its 3 separate todo line items)
const [todos, setTodos] = useState([
{
someText: "Learn a front end framework",
isCompleted: false
},
{ someText: "Learn a back end framework",
isCompleted: false
},
{
someText: " Deploy your project!",
isCompleted: false
},
]);



Lets unpack some of the things we've just done. React uses JSX for its syntax. You can think of it as combining regular JavaScript and regular HTML. By using JSX, React is different from most other front-end libraries/frameworks as you can write your business logic alongside your user interface in the same file and same function! For more information on JSX, take a look at React's official documentation.


On line 4, we defined a state variable, named todos and a function to control todos, named setTodos. The syntax for using the useState Hook is  [*state variable*, *function to set state variable*] = useState([..])

Beginning on line 6, we define 2 state props; someText (string type) and isCompleted (boolean type). Using "key:value" pairs, we created 3 static todos that'll appear when we run our application.


Creating TodoItem component

Next, we're going to make our first reusable component! One of the best features of React is to leverage reusable components. How often do you see websites/apps that have timelines/feeds, where each post has the same exact structure as you scroll through the website/app? The answer is: nearly all the time. React makes it easy to replicate the same behavior for our own application.

In your text editor/IDE, make a new file named TodoItem.js inside of the /components folder and open that file. This is where we define our TodoItem() component. It is considered a child component to the App() component, as the App() component is called before the its child, TodoItem() (like a family ancestral tree). Copy, paste, and save the following in TodoItem.js:

//Functional component; returns HTML containing the "someText" property of the "todo" prop and 2 buttons (props in React are like arguments in Python)
function TodoItem({ todo, index, completeTodo, removeTodo }){
return(
<div className="row p-2">
<div className="col">
{/* //if todo.isCompleted is true, add a line-through styling. if not, no styling */}
<div className="todo" style={{ textDecoration: todo.isCompleted ? "line-through" : "" }} >
{todo.someText}
<button type="button" className="mx-2 btn btn-primary" onClick={() => completeTodo(index)}>Complete</button>
<button type="button" className="mx-2 btn btn-danger" onClick={() => removeTodo(index)}>X</button>
</div>
</div>
</div>
);
};

export default TodoItem;


This component is smaller and easier to understand in comparison to it's parent component, App(). In line 2, we define our functional component and its props, todo, index, completeTodo, and removeTodo. Each prop are specific values that are passed into the child component from its parent component, App(). From line 3 - 13, we return some HTML with Bootstrap styling. In short, the return() method is where you design the user interface of your component. Take a close look at line 7 - 10 and notice how we use the props passed into this child component as well as how we call specific functions when a button is clicked. We use JavaScript arrow function expressions, for more information on arrow syntax, here is a good explanation. The last line in the file is to export the component, so it can be used in our components throughout our application.


TodoItem() is small in comparison to our App() component, so you may thinking, "why separate each component"? From a technical perspective, you are not required to have a separate file for each component in your React application. However, as a code base grows over time with new features, it is considered a good practice to separate each component. One rule of thumb I personally follow to determine if I should separate a component into its own file is how I design my user interface. If a component is a specific part of my UI (TodoItem() renders each individual todo) then it should separate into its own file and imported in it's parent component. The parent component will be responsible for controlling the behavior of the child component.

Exploring App.js (Part 2) 

Go back to our App.js file, lets import the TodoItem() component we just created. Copy and paste the following at the top of the App.js

import React, { useState } from 'react';
import './App.css';
import TodoItem from './components/TodoItem';


Lets add some functionality to our application. Copy, paste, and save the following code. Place it directly under where we last left off in the snippet of App() you copy and pasted earlier:

//Function to set the "isCompleted" boolean to true for a todo line item
const completeTodo = index => {
const someCompletedTodos = [...todos];
someCompletedTodos[index].isCompleted = true;
setTodos(someCompletedTodos);
};

// Function to remove a line item from the list(or array) of Todos
const removeTodo = index => {
const someRemovedTodos = [...todos];
someRemovedTodos.splice(index, 1);
setTodos(someRemovedTodos);
};


Here we defined 2 functions, completeTodo and removeTodo. Here is a deeper dive into each function:

completeTodo:

  • We take in the index of our rendered TodoItem component so our application knows which specific item to update.
  • We define a local variable, someCompletedTodos and make its value equal to the list of todos (our state variable)
  • For the todo in our local variable someCompletedTodos at some specific index, set its isCompleted prop to true
  • Call the setTodos function using the values of the local variable someCompletedTodos

removeTodo:

  • We take in the index of our rendered TodoItem component so our application knows which specific item to update.
  • We define a local variable, someRemovedTodos and make its value equal to the list of todos (our state variable)
  • For the todo in our local variable someRemovedTodos at some specific index, remove 1 todo from our local variable someRemovedTodos
  • Call the setTodos function using the values of the local variable someRemovedTodos


To complete our App() component, we need to actually render some UI. At the bottom of our App(), copy and paste the following:

return (
<div className="app">
<div className="todo-list">
{todos.map((todo, index) => ( //map() is used to create an array of items, use it render an array (such as "todos" variable).
//In other words, it creates an array of "Todo" functional components
<TodoItem
key={index}
index={index}
todo={todo}
completeTodo={completeTodo}
removeTodo={removeTodo}
/>
))}
</div>
</div>
);
}

export default App;


In our render() method, we created a few <div> to add some organization to our HTML, but take close look at line 4 and line 6. Line 4 is highlights one of React's strong-suits that you can combine business logic with UI. At line 4, we're creating an array/list of todos and giving each individual todo an unique identifier, called index. Starting in line 6, we actually render our TodoItem() component, passing in all the required props that TodoItem() needs (just like how we defined our child component).

Creating InputTodo component

Wouldn't it be great to have some user input in our app? Of course! Lets create a component that'll take in some user input and we can add an item to our todo state variable (effectively creating a larger list). 

In your text editor/IDE, make a new file named InputTodo.js inside of the /components folder, open the file. This is where we'll define our InputTodo() component. Similar to the TodoItem() component, InputTodo() is also a child component to App(). Copy, paste, and save the following:

import React, { useState } from 'react';

function InputForm({ addTodo }){
const [value, setValue] = useState(""); //creates a state object named "value", defaults it to an empty string
const handleSubmit = e => {
e.preventDefault(); //disables the default action of submitting a form
if (!value) return; //If theres no value, return (do nothing)
addTodo(value); //takes the value from the "addTodo" prop, sets that value to the "value" state
setValue(""); //resets the "value" state to an empty string
};
return (
<form onSubmit={handleSubmit}>
<div className='form-row'>
<div className='col-4'>
<input
type="text"
className="form-control"
value={value}
onChange={e => setValue(e.target.value)}
/>
<button type="button" className="mx-2 btn btn-success" onClick={handleSubmit}>Submit</button>
</div>
</div>
</form>
);
};

export default InputForm;


There is few things to explain in this component. This child component also has it's own state variable, value. We're using the useState() Hook to control the value of value.

This child component only takes in 1 prop from its parent component, addTodo. Remember, the plan is to have this component rendered from the App() component and have some value (defined in InputTodo() as addTodo) passed into it so we can manipulate it.

We also define a function within our component, handleSubmit. handleSubmit is required as our render() method uses an JSX form and we submit a form in React, we must provide some functionality on how to actually handle a form submission. Here is a breakdown of handleSubmit:

handleSubmit:

  • Takes in a value, e. e is shorthand for event and is a default JavaScript method that is available whenever an input event is called. e holds the value of the input field. For more information, take a look at this explanation.
  • Prevents the default action of submitting a form
  • If theres no value for our state variable value (if there isn't any characters typed in our input field), end the function and return nothing
  • If there is a value given to the function from the addTodo prop, set the value of our state variable value to the value of addTodo
  • Set the value of our state variable, value (our input field) to an empty string, resetting our input field

Finally, we build the UI for our component, using some Bootstrap styling. Take a close look our how we define our input tag using the current value of our state variable, value and how we call setValue(). Lastly, in the last line of the file, we export the component so we can reuse it throughout our application.

Exploring App.js (Part 3) 

Go back to our App.js file, lets import the InputTodo() component we just created. At the top of the file, copy and paste the following:

import React, { useState } from 'react';
import './App.css';
import TodoItem from './components/TodoItem';
import InputForm from './components/InputForm';


Now lets render the InputTodo() component. (Important note: You can render the component anywhere in the UI as you want, thats the power of isolating each component as reusable, child components). Copy and paste the following in our render() method within our App() component:

return (
<div className="app">
<div className="todo-list">
{todos.map((todo, index) => ( //map() is used to create an array of items, use it render an array (such as "todos" variable).
//In other words, it creates an array of "Todo" functional components
<TodoItem
key={index}
index={index}
todo={todo}
completeTodo={completeTodo}
removeTodo={removeTodo}
/>
))}
<InputForm addTodo={newTodo}/>
</div>
</div>
);
}

export default App;


Launching our Application! 

Make sure you've saved all files we worked on. Go to you cmd/terminal, enter the following command to start your local development server:

$npm start


You should see all the components we've built and have the ability to check off todos, remove todos, and add todos. Congratulations, this start of your developer journey! Here is a completed project here in StackBlitz:


About The Lab

Like the content posted on this site? Need help with another web project? Want to give some feedback? Feel free to contact me via email or social media!

Know more!
DigitalOcean Referral Badge