TO-DO APP USING REACT, VITE, AND BOOTSTRAP - PART 4: EDIT TASKS
In React Mar 31, 2024
Updated on April 3, 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>