<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Abhishek Arankal</title>
    <description>The latest articles on DEV Community by Abhishek Arankal (@abhishek_arankal_4ac78c11).</description>
    <link>https://dev.to/abhishek_arankal_4ac78c11</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3708860%2Fa08ce6c6-1a01-430f-958a-8e13f61f18ed.png</url>
      <title>DEV Community: Abhishek Arankal</title>
      <link>https://dev.to/abhishek_arankal_4ac78c11</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/abhishek_arankal_4ac78c11"/>
    <language>en</language>
    <item>
      <title>Todo App</title>
      <dc:creator>Abhishek Arankal</dc:creator>
      <pubDate>Thu, 15 Jan 2026 12:08:00 +0000</pubDate>
      <link>https://dev.to/abhishek_arankal_4ac78c11/todo-app-4m0a</link>
      <guid>https://dev.to/abhishek_arankal_4ac78c11/todo-app-4m0a</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;After completing my first logic-focused project (Counters), I wanted to take the next natural step in complexity — not by improving the UI, but by challenging my thinking.&lt;/p&gt;

&lt;p&gt;This led me to Project 2: Todo App (Logic-First, Not UI).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why a Todo App?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Counters helped me understand single-value state logic.&lt;br&gt;
A Todo app forces you to think in terms of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Arrays instead of single values&lt;/li&gt;
&lt;li&gt;CRUD operations (add, update, delete)&lt;/li&gt;
&lt;li&gt;Conditional rendering&lt;/li&gt;
&lt;li&gt;Edge cases and state consistency&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is where many React learners start to struggle — which makes it the perfect place to grow.&lt;/p&gt;

&lt;p&gt;The goal of this project was not to build a fancy interface, but to strengthen my problem-solving approach, write predictable state updates, and handle real-world logic scenarios that appear in almost every frontend application.&lt;/p&gt;

&lt;p&gt;In this article, I’ll break down how I approached the Todo app step by step, the logic decisions I made, the mistakes I encountered, and what I learned by solving them.&lt;/p&gt;
&lt;h2&gt;
  
  
  Level-by-Level Development 🚀
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Level 1: Add Todo Creation with Validation&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Commit:&lt;/strong&gt; Level 1: Add todo creation with validation&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setTodos&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;([]);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setTask&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleSubmit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Enter task to add&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nf"&gt;setTodos&lt;/span&gt;&lt;span class="p"&gt;([...&lt;/span&gt;&lt;span class="nx"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
  &lt;span class="nf"&gt;setTask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;placeholder&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Add task..."&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; 
&lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setTask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"border rounded px-2 py-2 w-80 m-2"&lt;/span&gt;&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;
  &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleSubmit&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"border rounded p-2 w-25 cursor-pointer hover:bg-gray-400 hover:text-black"&lt;/span&gt;
&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  Add Task
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;TaskCard&lt;/span&gt; &lt;span class="na"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;idx&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;))}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Learnings:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Controlled Inputs&lt;/strong&gt;
Learned how to manage form inputs using useState, keeping the input    value fully controlled by React state.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Basic Validation&lt;/strong&gt;&lt;br&gt;
Added validation to prevent empty or whitespace-only todos from being added:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;if (task.trim() === ""){&lt;br&gt;
 alert("Enter task to add");&lt;br&gt;
 return;&lt;br&gt;
}&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Immutable State Updates (Arrays)&lt;/strong&gt;&lt;br&gt;
Used the spread operator to update the todos array:&lt;br&gt;
&lt;code&gt;jsx &lt;br&gt;
setTodos([...todos, task]);&lt;br&gt;
&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Resetting Input for Better UX&lt;/strong&gt;&lt;br&gt;
Cleared the input field after adding a todo:&lt;br&gt;
&lt;code&gt;setTask("");&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Rendering Dynamic Lists&lt;/strong&gt;&lt;br&gt;
Used map() to render todos dynamically:&lt;br&gt;
&lt;code&gt;{todos.map((todo, idx) =&amp;gt; (&lt;br&gt;
&amp;lt;TaskCard todo={todo} key={idx} /&amp;gt;&lt;br&gt;
))}&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Level 2: Delete Todo (Filter Logic)&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;commit:&lt;/strong&gt;Level2: Add delete todo functionality&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Goal:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Allow users to delete a todo&lt;/li&gt;
&lt;li&gt;Remove only the selected todo&lt;/li&gt;
&lt;li&gt;Keep the remaining todos safe&lt;/li&gt;
&lt;li&gt;Learn proper state removal logic in React&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Core Idea:&lt;/strong&gt;&lt;br&gt;
Instead of modifying the existing todos array, create a &lt;strong&gt;new array(updatedTodos)&lt;/strong&gt; that excludes the selected todo and update the state with it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Logic:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleDeleteTask&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;selectedTodo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;updatedTodos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;selectedTodo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nf"&gt;setTodos&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;updatedTodos&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;&lt;span class="s2"&gt;`

&amp;lt;button className='px-2 py-0.5 border rounded text-sm bg-red-300 text-black' onClick={() =&amp;gt;handleDelete(todo)}&amp;gt;Delete&amp;lt;/button&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Learnings:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Deleting a Todo the Right Way:&lt;/strong&gt; 
Used filter() to remove a specific todo instead of changing the original array.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Why Not Use Index:&lt;/strong&gt;
Using index can cause bugs when items are added or removed.
So I deleted todos using a unique id, which is safer and more reliable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Understanding Immutability:&lt;/strong&gt;
filter() creates a new array instead of changing the old one.
This follows React’s rule of not mutating state directly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Predictable State Updates:&lt;/strong&gt;
Even after deleting multiple todos, the state stays clean and behaves as expected.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Level 3: Completing a Task (State Toggle Logic in React)&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;commit:&lt;/strong&gt; Level 3: Add toggle completed functionality&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Goal:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Mark a todo as completed or not completed&lt;/li&gt;
&lt;li&gt;Delete a specific todo&lt;/li&gt;
&lt;li&gt;Handle state updates safely&lt;/li&gt;
&lt;li&gt;Improve logic without breaking existing features&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Logic:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleTaskCompleted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;updatedTodos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;{...&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;completed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;completed&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nf"&gt;setTodos&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;updatedTodos&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'w-5 h-5 border'&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;handleTaskCompleted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;completed&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"text-md font-bold leading-none"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;✔&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Learnings:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Toggling State Using map():&lt;/strong&gt;
Used map() to update only the clicked todo without affecting others.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Conditional Rendering:&lt;/strong&gt;
Displayed the ✔ mark only when completed is true.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deleting a Todo Safely:&lt;/strong&gt;
Used filter() to remove a specific todo from state.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Avoiding Index-Based Bugs:&lt;/strong&gt;
Used a unique id instead of array index for both toggle and delete logic.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Immutability in React State:&lt;/strong&gt; 
Both map() and filter() return new arrays, keeping state updates safe.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Level 4: Editing a Task (Inline Edit Logic in React)&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;commit:&lt;/strong&gt; Level 4: Add edit todo functionality with id-based edit state&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Goal:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Edit a todo task directly inside the UI&lt;/li&gt;
&lt;li&gt;Allow only one task to be edited at a time&lt;/li&gt;
&lt;li&gt;Save updated task text safely&lt;/li&gt;
&lt;li&gt;Cancel editing without changing data&lt;/li&gt;
&lt;li&gt;Prevent empty or unchanged task updates&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Logic:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;App.jsx Logic:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;isEditingId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setIsEditingId&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleEditSave&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;editedTask&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;trimmedTask&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;editedTask&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;trimmedTask&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;trimmedTask&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;()){&lt;/span&gt;
    &lt;span class="nf"&gt;setIsEditingId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;updatedTodos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;{...&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;task&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;trimmedTask&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nf"&gt;setTodos&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;updatedTodos&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nf"&gt;setIsEditingId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;TaskCard.jsx Logic:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;editedTask&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setEditedTask&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;editingId&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
      &lt;span class="nf"&gt;setEditedTask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;editingId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="c1"&gt;//rendering logic&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;editingId&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt;
      &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;editedTask&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setEditedTask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;handleEditSave&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;editedTask&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      Save
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setIsEditingId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      Cancel
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setIsEditingId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    Edit
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;)}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Faced Bug:&lt;/strong&gt;&lt;br&gt;
At first, I used a global boolean value (true / false) to control edit mode.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;const [isEditing, setIsEditing] = useState(false)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When isEditing was set to true:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;All task cards entered edit mode&lt;/li&gt;
&lt;li&gt;Every task showed an input field at the same time&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;This happened because:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;All task cards were using the same edit state&lt;/li&gt;
&lt;li&gt;There was no way to know which task was being edited&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Bug Fix:&lt;/strong&gt;&lt;br&gt;
Instead of using a boolean, I changed the logic to use an &lt;strong&gt;id-based(uniqueId)&lt;/strong&gt; edit state.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;const [isEditingId, setIsEditingId] = useState(null)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Now:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;isEditingId stores the id of the task being edited&lt;/li&gt;
&lt;li&gt;Only the matching task card enters edit mode&lt;/li&gt;
&lt;li&gt;Other task cards remain unchanged&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;"Small bug, big learning 🚀"&lt;br&gt;
This change made my edit feature clean, predictable, and scalable.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Learnings:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Problem with using true/false state:&lt;/strong&gt; Using a single boolean caused all task cards to enter edit mode.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Id-Based Control:&lt;/strong&gt; Using a task id allows precise control over UI behavior.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scoped State Logic:&lt;/strong&gt; State should represent what is being edited, not just if editing exists.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Safe State Updates:&lt;/strong&gt; map() updates only the selected todo without affecting others.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Controlled Inputs:&lt;/strong&gt; Local input state makes editing predictable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Avoiding Index Bugs:&lt;/strong&gt; Using unique id is safer than array index.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Level 5: Task Filtering Logic (All/ Active / Completed)&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;commit:&lt;/strong&gt; Level 5: Add todo filters (all, active, completed)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Goal:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Show tasks based on their status&lt;/li&gt;
&lt;li&gt;Support All, Active, and Completed filters&lt;/li&gt;
&lt;li&gt;Keep filtering logic simple and safe&lt;/li&gt;
&lt;li&gt;Avoid breaking existing task features&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Logic:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setFilter&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;all&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;//filterTask logic&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;filteredTasks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filter&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;active&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;completed&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filter&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;completed&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;completed&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;flex items-center justify-around mt-5&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`px-3 py-1 border rounded w-25 text-black font-semibold cursor-pointer &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;filter&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;all&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bg-orange-300&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bg-white&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"all"&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setFilter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;All&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`px-3 py-1 border rounded w-25 text-black font-semibold cursor-pointer &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;filter&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;active&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bg-orange-300&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bg-white&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"active"&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setFilter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Active&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`px-3 py-1 border rounded w-25 text-black font-semibold cursor-pointer &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;filter&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;completed&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bg-orange-300&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bg-white&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"completed"&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setFilter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Completed&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;/&lt;/span&gt;&lt;span class="na"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;How it Works:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;filter() loops through all todos&lt;/li&gt;
&lt;li&gt;Based on the selected filter:

&lt;ul&gt;
&lt;li&gt;Active → shows tasks that are not completed&lt;/li&gt;
&lt;li&gt;Completed → shows only completed tasks&lt;/li&gt;
&lt;li&gt;All → returns every task&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Returning true keeps the task in the list&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Learnings:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Using filter():&lt;/strong&gt; Helps create a new list without changing the original state&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Conditional Logic:&lt;/strong&gt; Makes filtering flexible and easy to read&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Boolean Checks:&lt;/strong&gt; Clear boolean checks help prevent logic mistakes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Safe State Usage:&lt;/strong&gt; Filtering does not mutate the original array&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Clear UI Control:&lt;/strong&gt; Filter value directly controls what the user sees&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Optimizing Task Filtering Using useMemo&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;commit:&lt;/strong&gt; Optimize task filtering using useMemo&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Goal:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Improve performance of task filtering&lt;/li&gt;
&lt;li&gt;Avoid unnecessary recalculations on every render&lt;/li&gt;
&lt;li&gt;Keep logic clean and readable&lt;/li&gt;
&lt;li&gt;Optimize without changing existing behavior&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Problem Before Optimization:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Filtering logic ran on every render&lt;/li&gt;
&lt;li&gt;Even when todos and filter didn’t change&lt;/li&gt;
&lt;li&gt;This can affect performance as the app grows&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Optimized Logic:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useMemo&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;filteredTasks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useMemo&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filter&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;active&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;completed&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filter&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;completed&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;completed&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;How useMemo Helps:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;React remembers the filtered result&lt;/li&gt;
&lt;li&gt;Recalculates only when:

&lt;ul&gt;
&lt;li&gt;todos changes&lt;/li&gt;
&lt;li&gt;filter changes&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Prevents extra work during re-renders&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Level 6 – Edge Case Hardening&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;commit:&lt;/strong&gt; Level 6: Handle edge cases, duplicates&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Goal:&lt;/strong&gt;&lt;br&gt;
Make the app stable and user-proof by handling scenarios users commonly break apps with.&lt;/p&gt;

&lt;p&gt;At this stage, my Todo app already supported:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add&lt;/li&gt;
&lt;li&gt;Delete&lt;/li&gt;
&lt;li&gt;Edit&lt;/li&gt;
&lt;li&gt;Complete&lt;/li&gt;
&lt;li&gt;Filters (All / Active / Completed)
But it still had hidden problems.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Problems Before Level 6:&lt;/strong&gt;&lt;br&gt;
Here’s what could go wrong:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Users could add duplicate todos&lt;/li&gt;
&lt;li&gt;Extra spaces could sneak into task text&lt;/li&gt;
&lt;li&gt;UI looked broken when the list was empty&lt;/li&gt;
&lt;li&gt;Filters showed nothing with no explanation&lt;/li&gt;
&lt;li&gt;Edit/save edge cases could behave oddly&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are real UX and logic bugs, not beginner mistakes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What I Implemented in Level 6:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;1️⃣. Prevent Duplicate Todos&lt;br&gt;
Before adding a task, I checked if it already exists (case-insensitive):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleSubmit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
        &lt;span class="nf"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Enter task to add&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;checkTodoExists&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;some&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;checkTodoExists&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
        &lt;span class="nf"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Task Already Exists&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;setTask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;setTodos&lt;/span&gt;&lt;span class="p"&gt;([...&lt;/span&gt;&lt;span class="nx"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="na"&gt;task&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="na"&gt;completed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;}])&lt;/span&gt;
        &lt;span class="nf"&gt;setTask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If it exists:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Block the add&lt;/li&gt;
&lt;li&gt;Show a message&lt;/li&gt;
&lt;li&gt;Keep state safe&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This ensures:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No logical duplicates&lt;/li&gt;
&lt;li&gt;Cleaner data&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;2️⃣. Trim Input Everywhere&lt;br&gt;
I enforced trimming:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;While adding&lt;/li&gt;
&lt;li&gt;While editing
This stores data always clean:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;task.trim()&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;No accidental " Learn React " values anymore&lt;/p&gt;

&lt;p&gt;3️⃣ Empty State UI (Very Important UX)&lt;br&gt;
Instead of rendering nothing, I added a clear empty state:&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;code&gt;No tasks yet. Add one above 👆&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;This applies to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;First-time users&lt;/li&gt;
&lt;li&gt;After clearing all tasks&lt;/li&gt;
&lt;li&gt;When filters return no results
This alone made the app feel more professional.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Learnings:&lt;/strong&gt;&lt;br&gt;
"Edge cases are not rare — they are guaranteed.”&lt;br&gt;
Level 6 taught me to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Think defensively&lt;/li&gt;
&lt;li&gt;Validate data before storing&lt;/li&gt;
&lt;li&gt;Treat UX as part of logic&lt;/li&gt;
&lt;li&gt;Prevent bugs instead of fixing them later&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Level 7 – Persisting Todos with localStorage&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;commit:&lt;/strong&gt; Level 7: Persist todos using localStorage&lt;/p&gt;

&lt;p&gt;After Level 6, my app was stable — but refreshing the page still wiped everything.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Goal:&lt;/strong&gt;&lt;br&gt;
Make todos persist across page refreshes using localStorage.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What I Implemented in Level 7&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;1️⃣ Load Todos on App Mount&lt;br&gt;
When the app loads, read saved todos from localStorage:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;loaded&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setLoaded&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;//hydration&lt;/span&gt;
&lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;localStorageTodosData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;todosData&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;parsedlocalStorageTodosData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;localStorageTodosData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;parsedlocalStorageTodosData&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="nf"&gt;setTodos&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;parsedlocalStorageTodosData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nf"&gt;setLoaded&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This runs only once.&lt;br&gt;
Hydration → putting stored data back into React state&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What goes wrong WITHOUT loaded?&lt;/strong&gt;&lt;br&gt;
Order of events when app starts:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;React renders with: todos = []&lt;/li&gt;
&lt;li&gt;useEffect([todos]) runs

&lt;ul&gt;
&lt;li&gt;Saves empty array to localStorage ❌&lt;/li&gt;
&lt;li&gt;Old todos are LOST&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Then load effect runs

&lt;ul&gt;
&lt;li&gt;Too late — data already overwritten&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;2️⃣ Save Todos on Every Change&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;loaded&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
       &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;todosData&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;loaded prevents React from saving empty state before loading real data.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Now the flow becomes:&lt;/strong&gt;&lt;br&gt;
localStorage → React state → UI&lt;br&gt;
UI change → React state → localStorage&lt;/p&gt;

&lt;p&gt;3️⃣ Persist ONLY What Matters&lt;br&gt;
I intentionally did NOT store:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Filters&lt;/li&gt;
&lt;li&gt;Editing state&lt;/li&gt;
&lt;li&gt;Input text&lt;/li&gt;
&lt;li&gt;UI-only flags&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Only this was persisted: &lt;code&gt;todos&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What I Tested:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add → refresh → still exists ✅&lt;/li&gt;
&lt;li&gt;Delete → refresh → still deleted ✅&lt;/li&gt;
&lt;li&gt;Edit → refresh → updated text persists ✅&lt;/li&gt;
&lt;li&gt;Toggle completed → refresh → preserved ✅&lt;/li&gt;
&lt;li&gt;Clear completed → refresh → stays cleared ✅&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Learnings:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How to use useEffect properly&lt;/li&gt;
&lt;li&gt;How to hydrate state safely&lt;/li&gt;
&lt;li&gt;How to avoid overwriting data on first render&lt;/li&gt;
&lt;li&gt;The difference between data state and UI state&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why I Used Level-Based Commits
&lt;/h2&gt;

&lt;p&gt;I built this Task Manager using level-based commits, where each commit represents one concept or learning&lt;/p&gt;

&lt;p&gt;This helped me:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Track progress clearly&lt;/li&gt;
&lt;li&gt;Explain my logic easily in interviews&lt;/li&gt;
&lt;li&gt;Keep commits meaningful&lt;/li&gt;
&lt;li&gt;Show real learning on GitHub&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  GitHub Repository
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/Abhishek-Arankal/Smart-Task-Manager" rel="noopener noreferrer"&gt;https://github.com/Abhishek-Arankal/Smart-Task-Manager&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;This project taught me one important lesson:&lt;br&gt;
&lt;strong&gt;Logic improves through iteration, not complexity.&lt;/strong&gt;&lt;br&gt;
Instead of jumping to advanced features, I focused on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Building small&lt;/li&gt;
&lt;li&gt;Handling real edge cases&lt;/li&gt;
&lt;li&gt;Fixing bugs intentionally&lt;/li&gt;
&lt;li&gt;Writing predictable logic&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I’ll continue building small projects, documenting mistakes, and learning in public.&lt;/p&gt;

&lt;p&gt;If you see a better or cleaner way to write this logic,&lt;br&gt;
I’d genuinely appreciate your feedback 🙌&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>javascript</category>
      <category>react</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Building a Multi-Counter App in React — Improving Logic Step by Step</title>
      <dc:creator>Abhishek Arankal</dc:creator>
      <pubDate>Wed, 14 Jan 2026 13:54:37 +0000</pubDate>
      <link>https://dev.to/abhishek_arankal_4ac78c11/building-a-multi-counter-app-in-react-improving-logic-step-by-step-53bf</link>
      <guid>https://dev.to/abhishek_arankal_4ac78c11/building-a-multi-counter-app-in-react-improving-logic-step-by-step-53bf</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;To improve my logic-thinking and problem-solving skills, I decided to stop jumping directly into complex projects.&lt;br&gt;
Instead, I started building small projects and improving them level by level, focusing more on logic than UI.&lt;/p&gt;

&lt;p&gt;This article documents my journey of building a Multi-Counter Application in React, where each Git commit represents one learning.&lt;/p&gt;

&lt;p&gt;The goal was simple:&lt;br&gt;
Build logic incrementally, face real bugs, debug them, and learn deeply.&lt;/p&gt;
&lt;h2&gt;
  
  
  Project Overview
&lt;/h2&gt;

&lt;p&gt;The Multi-Counter App allows users to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Increment and decrement counters&lt;/li&gt;
&lt;li&gt;Apply minimum and maximum constraints&lt;/li&gt;
&lt;li&gt;Disable buttons based on logic&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Reset counters&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Correctly handle multiple counters without shared-state bugs&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each feature was added as a new level, not all at once.&lt;/p&gt;
&lt;h2&gt;
  
  
  Tech Stack
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;React.js&lt;/li&gt;
&lt;li&gt;JavaScript (ES6)&lt;/li&gt;
&lt;li&gt;Tailwind CSS&lt;/li&gt;
&lt;li&gt;Git &amp;amp; GitHub&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Level-by-Level Development 🚀
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Level 1: Increment and Decrement&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Commit:&lt;/strong&gt; Level 1: Increment and Decrement&lt;br&gt;
started with a basic counter using useState.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;const [count, setCount] = useState(0)&lt;br&gt;
const handleIncrement = () =&amp;gt; setCount(count + 1);&lt;br&gt;
const handleDecrement = () =&amp;gt; setCount(count - 1);&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Learning:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How React state updates work&lt;/li&gt;
&lt;li&gt;How UI re-renders on state change&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Level 2: Minimum Constraint &amp;amp; Disable Decrement Button&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Commit:&lt;/strong&gt; Level 2: Minimum Constraint and disabled button&lt;br&gt;
I prevented the counter from going below 0 and disabled the decrement button when the value reached the minimum.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;const handleDecrement = () =&amp;gt; {&lt;br&gt;
    if(count &amp;gt; 0) {&lt;br&gt;
      setCount(count - 1)&lt;br&gt;
    }&lt;br&gt;
  }&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;disabled&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Decrement&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Learning:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Handling edge cases&lt;/li&gt;
&lt;li&gt;Controlling UI with conditions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Level 3: Maximum Constraint &amp;amp; Disable Increment Button&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Commit:&lt;/strong&gt; Level 3: Maximum Constraint and Disable Increment Button&lt;br&gt;
I added a maximum limit and disabled the increment button once the limit was reached.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;const handleIncrement = () =&amp;gt; {&lt;br&gt;
    if(count &amp;lt; 10){&lt;br&gt;
      setCount(count + 1)&lt;br&gt;
    }&lt;br&gt;
  }&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;disabled&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Increment&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Learning:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Defensive programming&lt;/li&gt;
&lt;li&gt;Syncing UI with business logic&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Level 4: Reset Functionality&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Commit:&lt;/strong&gt; Level 4: Reset Functionality&lt;br&gt;
Added a reset button to bring the counter back to its initial value.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;const handleReset = () =&amp;gt; setCount(0);&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'px-4 py-2 bg-yellow-600 rounded hover:bg-yellow-700 transition'&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setCount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Reset&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Learning:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Clean state reset patterns&lt;/li&gt;
&lt;li&gt;Better user experience&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Level 8: Fix Increment Logic for Multiple Counters&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Commit:&lt;/strong&gt; Level 8: Fix increment logic for multiple counters&lt;br&gt;
This was the most important level.&lt;/p&gt;

&lt;p&gt;When I introduced multiple counters, I initially faced serious logic bugs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;State updates behaved unpredictably&lt;/li&gt;
&lt;li&gt;Incrementing one counter affected others&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Debugging: counters.map is not a function in React&lt;/strong&gt;&lt;br&gt;
While working on the increment logic for multiple counters, I encountered a confusing runtime error:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;❌ &lt;strong&gt;Runtime Error:&lt;/strong&gt; &lt;code&gt;counters.map is not a function&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Initial Implementation&lt;/strong&gt;&lt;br&gt;
Initially, my handleIncrement function looked like this:&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;code&gt;const [counters, setCounters] = useState([&lt;br&gt;
    {id:1, value:0},&lt;br&gt;
    {id:2, value:0},&lt;br&gt;
    {id:3, value:0}&lt;br&gt;
  ])&lt;br&gt;
const handleIncrement = (id) =&amp;gt; {&lt;br&gt;
    setCounters((prevCounters) =&amp;gt; {&lt;br&gt;
       prevCounters.map((counter) =&amp;gt; counter.id === id ? {...counter, value: counter.value &amp;lt; 10 ? counter.value + 1 : counter.value} : counter)&lt;br&gt;
    })&lt;br&gt;
  }&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Issue:&lt;/strong&gt; &lt;code&gt;counters.map is not a function&lt;/code&gt;&lt;br&gt;
After clicking the increment or decrement button for the first time, the application crashed with the following error:&lt;br&gt;
    counters.map is not a function&lt;br&gt;
This error did not happen during the click itself.&lt;br&gt;
It occurred during the next render cycle, when React tried to re-render the UI.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What Happened Internally&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A button click triggered setCounters&lt;/li&gt;
&lt;li&gt;React updated the state&lt;/li&gt;
&lt;li&gt;React attempted to re-render the UI&lt;/li&gt;
&lt;li&gt;During rendering, this line executed: &lt;code&gt;counters.map(...)&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;At that moment, counters was no longer an array
This caused the runtime error and broke the UI.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Root Cause&lt;/strong&gt;&lt;br&gt;
The problem was a missing return statement.&lt;/p&gt;

&lt;p&gt;Because I used curly braces {} in the arrow function passed to setCounters, JavaScript does not return anything by default.&lt;/p&gt;

&lt;p&gt;As a result:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The function returned undefined&lt;/li&gt;
&lt;li&gt;React set counters state to undefined&lt;/li&gt;
&lt;li&gt;On the next update, calling .map() caused the error&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The Fix&lt;/strong&gt;&lt;br&gt;
First, I went through the code line by line and logged the value of counters using console.log(counters) after clicking the increment button.&lt;/p&gt;

&lt;p&gt;I noticed that counters was becoming undefined, which indicated that the state updater function was not returning any value.&lt;/p&gt;

&lt;p&gt;After identifying this, I explicitly returned the new array produced by map(), which fixed the issue.&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;code&gt;const handleIncrement = (id) =&amp;gt; {&lt;br&gt;
    setCounters((prevCounters) =&amp;gt; {&lt;br&gt;
       return prevCounters.map((counter) =&amp;gt; counter.id === id ? {...counter, value: counter.value &amp;lt; 10 ? counter.value + 1 : counter.value} : counter)&lt;br&gt;
    })&lt;br&gt;
  }&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why This Works&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;map() returns a new array&lt;/li&gt;
&lt;li&gt;return ensures React receives valid state&lt;/li&gt;
&lt;li&gt;Only the clicked counter updates&lt;/li&gt;
&lt;li&gt;State remains immutable&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Core Logic Explained&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;code&gt;const handleIncrement = (id) =&amp;gt; {&lt;br&gt;
    setCounters((prevCounters) =&amp;gt; {&lt;br&gt;
       return prevCounters.map((counter) =&amp;gt; counter.id === id ? {...counter, value: counter.value &amp;lt; 10 ? counter.value + 1 : counter.value} : counter)&lt;br&gt;
    })&lt;br&gt;
  }&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This logic:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Updates only one counter&lt;/li&gt;
&lt;li&gt;Keeps others unchanged&lt;/li&gt;
&lt;li&gt;Follows React’s immutability rules&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Challenges Faced&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;State becoming undefined&lt;/li&gt;
&lt;li&gt;Shared-state bugs with multiple counters&lt;/li&gt;
&lt;li&gt;Forgetting how arrow functions return values&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;What I Learned&lt;/strong&gt; &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Most React bugs are JavaScript logic bugs&lt;/li&gt;
&lt;li&gt;Missing return can silently break state&lt;/li&gt;
&lt;li&gt;map is not a function usually means state is corrupted&lt;/li&gt;
&lt;li&gt;Small projects expose real-world issues&lt;/li&gt;
&lt;li&gt;Level-based learning builds confidence&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Why I Used Level-Based Commits&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Each commit = one learning&lt;/li&gt;
&lt;li&gt;Easy to explain in interviews&lt;/li&gt;
&lt;li&gt;Clear progress tracking&lt;/li&gt;
&lt;li&gt;Meaningful GitHub activity&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  GitHub Repository
&lt;/h2&gt;

&lt;p&gt;GitHub: &lt;a href="https://github.com/Abhishek-Arankal/React-Counter" rel="noopener noreferrer"&gt;https://github.com/Abhishek-Arankal/React-Counter&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;This project taught me one important lesson:&lt;br&gt;
&lt;strong&gt;Logic improves through iteration, not complexity.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I’ll continue building small projects, documenting bugs, and learning in public.&lt;br&gt;
If you see a better way to write this logic, I’d love your feedback.&lt;/p&gt;

</description>
      <category>learninginpublic</category>
      <category>react</category>
      <category>javascript</category>
      <category>logicbuilding</category>
    </item>
  </channel>
</rss>
