DEV Community

Tim Winfred (They/He)
Tim Winfred (They/He)

Posted on • Updated on

Using the JavaScript `reduce` method to optimize my React To Do app

As part of my #100DaysOfCode challenge, I created a To Do app using React. From the outset, I felt confident about being able to complete the challenge quickly and without too many struggles. Thankfully, I was able to do so (for the most part).

The piece of the puzzle that took the longest was the sorting of the tasks. Specifically, the challenge asked to sort the tasks into three groups: overdue tasks at the top, unfinished tasks in the middle, and completed tasks at the bottom. Then, for each of those categories, the tasks should be sorted with the oldest tasks at the top.

My brain iterated through a variety of ways to sort the tasks, but here is the "first final" solution I came up with:

const sortTasks = (tasks: iTasks): iTasks => {
  const sortByDueDate = (a: iTask, b: iTask): number => {
    if (a.dueDate && b.dueDate) return Date.parse(a.dueDate) - Date.parse(b.dueDate);
    if (a.dueDate) return -1;
    if (b.dueDate) return 1;
    return 0;
  }

  const overdueTasks = tasks.filter(task => {
    return isOverdue(task.dueDate, task.isComplete);
  }).sort((a, b) => sortByDueDate(a, b));

  const toDoTasks = tasks.filter(task => {
    return !task.isComplete && !isOverdue(task.dueDate, task.isComplete);
  }).sort((a, b) => sortByDueDate(a, b));

  const completedTasks = tasks.filter(task => {
    return task.isComplete;
  }).sort((a, b) => sortByDueDate(a, b));

  return [...overdueTasks, ...toDoTasks, ...completedTasks];
};
Enter fullscreen mode Exit fullscreen mode

The biggest issue I had with this "final" solution was that for each type of task, I was iterating through the entire array of tasks. I knew there had to be some way of optimizing that part of the code...

Then, my dog woke me up earlier than usual this morning and I was sitting in bed ruminating on the issue (definitely a "nerd moment" haha). I pulled open the browser on my phone and did a search for javascript filter store unfiltered items as well, in an attempt to get the filtered and unfiltered results from the above solution.

That search led me to this Stack Overflow article entitled How to get "unfiltered" array items?. BAM... there was my solution!

After watching a few videos on how to used the JavaScript reduce method, and then playing around with the method on my own, I finally came up with this solution:

const sortTasks = (tasks: iTasks): iTasks => {
  let sortedTasks = tasks.reduce((accumulator: iTasks[], currentValue: iTask) => {
    const isTaskOverdue = isOverdue(currentValue.dueDate, currentValue.isComplete);

    if (isTaskOverdue) {
      accumulator[0].push(currentValue);
    } else if (!currentValue.isComplete && !isTaskOverdue) {
      accumulator[1].push(currentValue);
    } else {
      accumulator[2].push(currentValue);
    }

    return accumulator;
  }, [[], [], []]);

  const sortByDueDate = (tasks: iTasks): iTasks => {
    return tasks.sort((a, b) => {
      if (a.dueDate && b.dueDate) return Date.parse(a.dueDate) - Date.parse(b.dueDate);
      if (a.dueDate) return -1;
      if (b.dueDate) return 1;
      return 0;
    });
  };

  return [...sortByDueDate(sortedTasks[0]), ...sortByDueDate(sortedTasks[1]), ...sortByDueDate(sortedTasks[2])];
};
Enter fullscreen mode Exit fullscreen mode

This was my first time ever really playing around with the reduce method, and I feel pretty happy with the code change I made. If you have any suggestions for optimizing my code even further, please leave a comment and let me know or hit me up on Twitter at @Contimporary.

Oh, and for anybody who's curious, here are the YouTube videos I watched:

Also, for those curious, feel free to check out the code for the full app on my GitHub.

Happy Monday =)

Top comments (2)

Collapse
 
vberlier profile image
Valentin Berlier

It's better than what you had before but the whole thing could still be done with a single call to the sort method and a custom comparison function. Also you should avoid repeatedly calling Date.parse in the comparison function. On average the number of comparison is O(n log n) so your sortByDueDate function slows down the sorting algorithm tremendously by forcing it to do some date parsing every time it tries to compare two elements.

Collapse
 
twinfred profile image
Tim Winfred (They/He)

Thank you for the feedback. If you have time to share and wouldn't mind, I would love to see your solution!