“Tasks” array disappears when certain dispatchers are called (MERN stack)

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.logs 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;