TO-DO APP USING REACT, VITE, AND BOOTSTRAP - PART 3: CREATE TASKS
In React Mar 31, 2024
Updated on Mar 31, 2024
In this post, we will implement the ability to add new tasks.
ALL PARTS:
- To-Do App Using React, Vite, And Bootstrap: Set Up the Application
- To-Do App Using React, Vite, And Bootstrap: Create Custom Components
- To-Do App Using React, Vite, And Bootstrap: Create Tasks
- To-Do App Using React, Vite, And Bootstrap: Edit Tasks
- To-Do App Using React, Vite, And Bootstrap: Delete and Update Tasks Status
Create Tasks
Let's now implement the ability to add new tasks. We'll create another component that we'll call NewTask
. In the src
folder, let's add a NewTask.jsx
file where we'll put this component.
Let's edit this file as follows:
const NewTask = () => {
return (
<form className="mt-5">
<label htmlFor="task-title" className="form-label">
New Task
</label>
<input
type="text"
name="task-title"
id="task-title"
className="form-control"
required
/>
<button type="submit" className="btn btn-primary mt-3">
Add
</button>
</form>
);
};
export default NewTask;
Let's import this component into the Tasks
component. Below the other import statements, add this:
import NewTask from "./NewTask.jsx";
Then we can use it. Above the tasks list, put this:
<NewTask />
Now, we want to add the new task to the list when the form is submitted. For that, we'll create a function named handleSubmit
. This function will be attached to the onSubmit
event handler of the form, triggering when the form is submitted by the user.
Let's add this inside the NewTask
component, before the return
statement:
const handleSubmit = (e) => {
e.preventDefault();
};
Within this function, we call e.preventDefault()
to prevent the default form submission behavior, which typically results in a page refresh. By preventing this default action, we can handle the form submission entirely within our React application without disrupting the user experience.
Next, we attach the onSubmit
event handler to the form element in the JSX
, specifying onSubmit={handleSubmit}
:
<form className="mt-5" onSubmit={handleSubmit}>
...
</form>;
This ensures that when the form is submitted (e.g., by clicking the submit button), the handleSubmit
function will be invoked, allowing us to handle the form submission within our React application.
We want to get the value of the input field when the form is submitted. For this, we create a new state variable inside the NewTask
component. First, we need to import the useState
hook from React
:
import { useState } from "react";
Next, we'll define a state variable named task
and a corresponding function setTask
to update its value. This state variable will hold the value of the input field. Above the handleSubmit
function add this:
const [task, setTask] = useState("");
Now that we have the state variable set up, we can bind its value to the input field. We'll update the value
attribute of the input element to reflect the value of the task
state variable:
<input
type="text"
name="task-title"
id="task-title"
className="form-control"
value={task}
required
/>
By setting the value
attribute to task
, we ensure that the input field reflects the current value stored in the task
state variable. This allows us to capture and manipulate the user input effectively.
When passing a value
prop
to an input field, it's essential to include an onChange
event handler. This ensures that the input field's value can be updated based on user input. Without an onChange
handler, the input field would remain static, and user input would not be reflected in the component's state.
To synchronize the input field's value with the component's state, we use the onChange
event handler to capture user input and update the state accordingly. Inside the onChange
handler, we access the value of the input field via e.target.value
, where e
is the event object. We then use this value to update the state using the setTask
function.
Here's how the updated input element looks:
<input
type="text"
name="task-title"
id="task-title"
className="form-control"
value={task}
onChange={(e) => setTask(e.target.value)}
required
/>
To update the tasks list, we must pass the tasks
and the setTasks
from the Tasks
component to the NewTask
component. Let's edit it:
const NewTask = ({ tasks, setTasks }) => {
// Additional component logic
};
By destructuring the tasks
and setTasks props in the NewTask
component's function parameters, we ensure that these values are accessible within the component. This enables the NewTask
component to interact with the tasks list maintained by the parent Tasks
component and update it as needed.
We'll pass the tasks
state variable and the setTasks
function as props to the NewTask
component in the Tasks
component, to enable NewTask
to interact with and update the tasks list maintained by Tasks
. Here's the updated code:
<NewTask tasks={tasks} setTasks={setTasks} />
Including these props allows for effective communication between parent and child components in React, facilitating the passing of data and functions as needed for seamless interaction and state management.
Now, we can update the list when a new task is added. First, let's import uuid in the NewTask
component:
import { v4 as uuidv4 } from "uuid";
Now, let's update the handleSubmit
function:
const handleSubmit = (e) => {
e.preventDefault();
if (task.trim() === "") {
console.error("Task cannot be empty.");
return;
}
setTasks([
{ id: uuidv4(), title: task.trim(), completed: false },
...tasks,
]);
setTask("");
};
We first check if the trimmed task string is empty. If it is, we log an error message to the console and return early from the function.
If the task is not empty, we proceed to add it to the tasks array.
We use the uuidv4()
function from the uuid library to generate a unique ID for each new task.
We construct a new task
object with the generated ID, the trimmed title obtained from the task state variable, and a default completed value of false
.
We prepend the new task to the existing tasks list using the spread operator (...tasks
) within the setTasks
function. This ensures that the new task is added to the beginning of the list.
After adding the task, we clear the input field by setting the task
state variable to an empty string using setTask("")
.