I’m working on a MERN stack “to-do list” application which performs CRUD operations. There is Tasks list on one side of the screen and a form to add new tasks or edit existing tasks on the other side.
In order to edit a “task” from the list, I click on “Edit” button which is visible next to every single task, and the task title and description is getting fetched by the form. Then I edit those and save back to the database. There is no problem with the functionality.
However, after I click on Edit button, my Tasks list is getting completely disappeared with “No Tasks Found” and doesn’t come back until I refresh the page. This only happens while I’m editing an existing task. While I’m adding a new task, my Tasks list stays there and even new task is dynamically getting added to the bottom of the list.
This is a front-end problem that I couldn’t fix so far. I confirmed with console.log
s that Tasks are getting invisible on the UI but actually still there and functions without an issue. Also there are no error logs on my console. What I’ve noticed is: in order to fetch an existing task, I’ve created two dispatchers case 'SET_EDIT_MODE':
to start editing and case "CLEAR_EDIT_MODE":
to end editing after clicking Save. My Tasks array gets disappeared after these two dispatchers are being called.
I’m sharing related code snippets and I hope someone provide me a little help. Your time and effort will be appreciated.
taskReducer.js
file:
function taskReducer(tasks = [], action) {
console.log("taskreducer");
switch (action.type) {
// eslint-disable-next-line no-lone-blocks
case "ADD_TASK": {
return [
...tasks,
{
_id: action._id,
title: action.title,
description: action.description,
completed: false
}
]
}
case "SET_TASK": {
return action.payload
}
case "REMOVE_TASK": {
console.log("Tasks before removal:", tasks);
const updatedTasks = tasks.filter((task) => task._id !== action._id);
console.log("Tasks after removal:", updatedTasks);
return updatedTasks;
}
case "MARK_DONE": {
return tasks.map((task) => {
if (task._id === action._id) {
return {
...task,
completed: !task.completed
}
}
return task
})
}
case "EDIT_TASK": {
const { taskToEdit, title, description } = action;
// Ensure taskToEdit exists within tasks object
if (tasks && tasks.taskToEdit) {
const updatedTask = {
...tasks.taskToEdit,
title,
description
};
// Return a new object maintaining the original structure
return {
...tasks,
taskToEdit: {
...tasks.taskToEdit,
title,
description
},
[taskToEdit]: updatedTask // Update the specific task in the tasks object
};
}
return tasks; // Return original state if tasks or taskToEdit is missing
}
case 'SET_EDIT_MODE': {
console.log('Processing SET_EDIT_MODE:', action.payload);
return {
...tasks,
taskToEdit: action.payload, // Set the task for editing
editMode: true // Set edit mode to true
};
}
case "CLEAR_EDIT_MODE": {
console.log('Processing CLEAR_EDIT_MODE');
return {
...tasks,
taskToEdit: null,
editMode: false
};
}
default: {
throw Error("Unknown Action" + action.type)
}
}
}
export default taskReducer;
Task.jsx
component:
import React, { useContext } from 'react';
import moment from 'moment';
import "../styles/task.css";
import axios from "../axios/axios.js"
import TaskContext from '../context/TaskContext.js';
import TokenContext from '../context/TokenContext.js';
import DeleteIcon from '@mui/icons-material/Delete';
import EditIcon from '@mui/icons-material/Edit';
function Task({ task }) {
const { _id, title, description, completed } = task;
const { dispatch } = useContext(TaskContext);
const { userToken } = useContext(TokenContext);
... // Unrelated app logic
// Called clicking on Edit button
const handleEdit = () => {
console.log('Editing task:', { task }); // Log the task details being edited
// Dispatch an action to set the task for editing
console.log('Dispatching SET_EDIT_MODE with task:', task);
dispatch({
type: 'SET_EDIT_MODE',
payload: task // Send the entire task object for editing
});
};
... // Unrelated UI code
export default Task;
SaveTask.jsx
component:
import React, { useState, useEffect, useContext } from 'react';
import TaskContext from '../context/TaskContext';
import TokenContext from '../context/TokenContext';
import axios from "../axios/axios";
import "../styles/saveTask.css";
function SaveTask() {
const { tasks, dispatch } = useContext(TaskContext);
const { userToken } = useContext(TokenContext);
const [title, setTitle] = useState("");
const [description, setDescription] = useState("");
const { editMode, taskToEdit } = tasks; // Extract editMode and taskToEdit from context
useEffect(() => {
// Populate form fields with task details when in editMode
if (editMode && taskToEdit) {
setTitle(taskToEdit.title);
setDescription(taskToEdit.description);
} else {
setTitle(""); // Reset title when not editing
setDescription(""); // Reset description when not editing
}
}, [editMode, taskToEdit]);
// Form logic
const handleAddOrEdit = async (e) => {
e.preventDefault();
try {
if (editMode && taskToEdit) {
// Update existing task
const res = await axios.post(`/task/editTask/${taskToEdit._id}`, { title, description }, {
headers: {
Authorization: `Bearer ${userToken}`
}
});
console.log("Task edited:", res.data);
// Update task in context
dispatch({
type: 'EDIT_TASK',
_id: taskToEdit._id,
title: res.data.task.title,
description: res.data.task.description
});
dispatch({ type: 'CLEAR_EDIT_MODE' }); // Clear edit mode after submission
} else {
// Add new task
const res = await axios.post("/task/addTask", { title, description }, {
headers: {
Authorization: `Bearer ${userToken}`
}
});
console.log("New task added:", res.data);
// Add new task to context
dispatch({
type: "ADD_TASK",
_id: res.data.task._id,
title: res.data.task.title,
description: res.data.task.description,
});
}
// Reset form fields
setTitle("");
setDescription("");
} catch (error) {
console.log(error);
}
};
... // Form input fields
export default SaveTask;
AllTask.jsx
component:
import React, { useContext } from 'react';
import Task from './Task';
import TaskContext from '../context/TaskContext';
function AllTask() {
const { tasks, editMode, taskToEdit } = useContext(TaskContext);
console.log('Tasks:', tasks);
console.log('EditMode:', editMode);
console.log('TaskToEdit:', taskToEdit);
// Tasks list
return (
<div>
{Array.isArray(tasks) && tasks.length !== 0 ? (
tasks.map((task, index) => (
<Task key={index} task={task} id={index} />
))
) : (
<h1>No Tasks Found</h1>
)}
</div>
);
}
export default AllTask;