TO-DO APP USING REACT, VITE, AND BOOTSTRAP - PART 3: CREATE TASKS
In React Mar 31, 2024
Updated on June 8, 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("")
.