TO-DO APP USING REACT, VITE, AND BOOTSTRAP - PART 4: EDIT TASKS
In React Mar 31, 2024
Updated on June 8, 2024
In this part of the tutorial, we'll implement the ability to edit 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
Edit the Task
To enable editing, we'll need an edit button that will open a modal form.
First, in the Task
component, after the task title, let's add a
div element. Within this element, we'll add an edit button:
<div className="ms-auto">
<button className="btn btn-info btn-sm">Edit</button>
</div>
We'll put the modal in the Tasks component below the tasks list. We'll use the
Modal
component from the
react-bootstrap library. It provides a convenient and
pre-styled solution for creating modals in React applications. Let's import it
at the top of the file:
import Modal from "react-bootstrap/Modal";
Then, we can use it. Below the tasks lists put this:
<Modal>
<Modal.Header closeButton>
<Modal.Title>Edit Task</Modal.Title>
</Modal.Header>
<Modal.Body></Modal.Body>
</Modal>
For now, our modal only has only a title.
Currently, the modal is hidden, so a state variable is necessary to toggle its
visibility. In the Tasks
component, let's add such a
variable after the tasks
state variable:
const [showEdit, setShowEdit] = useState(false);
By setting the initial state to false
, the modal is initially
hidden when the component renders.
Now we can add these props to our modal:
<Modal show={showEdit} onHide={() => setShowEdit(false)}>
....
</Modal>
The show
prop determines whether the modal is displayed based on
the value of the showEdit
state variable, and the
onHide
prop specifies a function to be called when the modal is
hidden, in this case, setting the showEdit
state to false.
Then, we will set this variable state to true
, when the edit
button is clicked. In the Task
component, we'll define a
handleTaskEdit
function:
const handleTaskEdit = (task) => {
setShowEdit(true);
};
To ensure that the handleTaskEdit
function can access and update
the showEdit
state in the parent component (Tasks
),
we're passing down the setShowEdit
prop to the
Task component.
const Task = ({ task, setShowEdit }) => {
...
};
In the Tasks
component, we update the Task
component
by passing the setShowEdit
prop to it:
<Task key={task.id} task={task} setShowEdit={setShowEdit} />
And we attach an onClick
event handler to the
Edit button within the Task
component. This
event handler triggers the handleTaskEdit
function:
<button
className="btn btn-info btn-sm"
onClick={() => handleTaskEdit(task)}
>
Edit
</button>
When the user clicks the edit button, the showEdit
state is
updated to true
, causing the modal to be displayed.
Create an EditTask Component
We will put the edit modal in its own component. In the
src
folder, let's create a file called EditTask.jsx
.
Let's import the Modal
component from the
react-bootstrap library:
import Modal from "react-bootstrap/Modal";
We can remove this import from the Tasks
component.
And now let's create the EditTask
component:
const EditTask = ({ showEdit, setShowEdit }) => {
return (
<Modal show={showEdit} onHide={() => setShowEdit(false)}>
<Modal.Header closeButton>
<Modal.Title>Edit Task</Modal.Title>
</Modal.Header>
<Modal.Body></Modal.Body>
</Modal>
);
};
export default EditTask;
Now, we'll import it into the Tasks
component:
import EditTask from "./EditTask.jsx";
Then we can use it. Below the tasks lists, delete the
Modal
component add this:
<EditTask showEdit={showEdit} setShowEdit={setShowEdit} />
Within the Task
component's JSX
structure,
we've added the EditTask
component, passing it props such as
showEdit
and setShowEdit
. By modularizing the
edit task modal into its own component, we've improved code organization and
maintainability. We can now easily manage the edit task functionality
separately from other components, enhancing the overall structure of the
application.
Create an Edit Task Form
In the body of the modal, we'll add the edit form:
<form>
<label htmlFor="task-title" className="form-label">
Task Title
</label>
<input
type="text"
name="task-title"
id="task-title"
className="form-control"
required
/>
<button type="submit" className="btn btn-primary mt-3">
Save Changes
</button>
</form>
We want to edit the task we clicked on, so we'll need a state variable to
store this task ID. In the Tasks
component, add
this variable below the other state variables:
const [editedTaskId, setEditedTaskId] = useState(null);
Then, we pass the setEditedTaskId
as a prop to the
Task
component:
const Task = ({ task, setShowEdit, setEditedTaskId }) => {
...
);
In the Tasks
component, update the usage of the
Task
component:
<Task
key={task.id}
task={task}
setShowEdit={setShowEdit}
setEditedTaskId={setEditedTaskId}
/>
Now, in the handleTaskEdit
function, we set the
editedTaskId
state to the ID of this task,
ensuring that the correct task is targeted for editing.
const handleTaskEdit = (task) => {
setShowEdit(true);
setEditedTaskId(task.id);
};
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
Tasks
component.
We'll define a state variable named editedTask
and a
corresponding function setEditedTask
to update its value. This
state variable will hold the value of the input field. Below the other state
variables add this:
const [editedTask, setEditedTask] = useState("");
Then, we pass the setEditedTask
as a prop to the
Task
component:
const Task = ({ task, setShowEdit, setEditedTaskId, setEditedTask }) => {
...
};
Let's update the usage of this component in the Tasks
component:
<Task
key={task.id}
task={task}
setShowEdit={setShowEdit}
setEditedTaskId={setEditedTaskId}
setEditedTask={setEditedTask}
/>
Then, inside the handleTaskEdit
function, we set the
editedTask
variable to the value of the task title:
const handleTaskEdit = (task) => {
setShowEdit(true);
setEditedTaskId(task.id);
setEditedTask(task.title);
};
We'll pass the editedTask
and the
setEditedTask
props to the EditTask
component:
const EditTask = ({ showEdit, setShowEdit, editedTask, setEditedTask }) => {
...
};
In the Tasks
component, we'll update the usage of this component
as follows:
<EditTask
showEdit={showEdit}
setShowEdit={setShowEdit}
editedTask={editedTask}
setEditedTask={setEditedTask}
/>
We'll update the input
element to use the
editedTask
as value:
<input
type="text"
name="task-title"
id="task-title"
className="form-control"
value={editedTask}
onChange={(e) => setEditedTask(e.target.value)}
required
/>
By initializing the editedTask
state variable with the title of
the task that was clicked on, we ensure that the input field is pre-filled
with the current title when the modal is opened for editing. Also, we
use the onChange
event handler to update the input value via
e.target.value
.
In the EditTask
component, we'll create a
submitEdit
function that update the task:
const submitEdit = (e, id) => {
e.preventDefault();
if (editedTask.trim() === "") {
console.error("Task title cannot be empty");
return;
}
const updatedTasks = tasks.map((task) => {
if (task.id === id) {
return {
...task,
title: editedTask.trim(),
};
} else {
return task;
}
});
setTasks(updatedTasks);
setShowEdit(false);
};
This function iterates over the tasks list, and for the task with the matching
ID, it updates the title with the value from
editedTask
. Then it sets the updated tasks list using
setTasks
and hides the edit modal by setting
showEdit
to false.
In order for this function to work, we'll need to pass the
tasks
and the setTasks
props to the
EditTask
component:
const EditTask = ({
showEdit,
setShowEdit,
editedTask,
setEditedTask,
tasks,
setTasks,
}) => {
...
};
We'll also update the usage of the EditTask
component in the
Tasks
component:
<EditTask
showEdit={showEdit}
setShowEdit={setShowEdit}
editedTask={editedTask}
setEditedTask={setEditedTask}
tasks={tasks}
setTasks={setTasks}
/>
To update the task what was clicked on, we must pass the
editedTaskId
prop to the EditTask
component:
const EditTask = ({
showEdit,
setShowEdit,
editedTask,
setEditedTask,
tasks,
setTasks,
editedTaskId,
}) => {
...
};
In the Tasks
component, we update the usage of the
EditTask
component:
<EditTask
showEdit={showEdit}
setShowEdit={setShowEdit}
editedTask={editedTask}
setEditedTask={setEditedTask}
tasks={tasks}
setTasks={setTasks}
editedTaskId={editedTaskId}
/>
Then, we pass the submitEdit
function to the
onSumbit
event handler of the edit form:
<form onSubmit={(e) => submitEdit(e, editedTaskId)}>
...
</form>