<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ todoapp - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ todoapp - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Fri, 26 Jun 2026 04:50:44 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/todoapp/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to Build a MERN Stack To-Do App ]]>
                </title>
                <description>
                    <![CDATA[ This guide will walk you through building a full-stack MERN To-Do application. It covers setting up the environment, writing code to demonstrate core CRUD (Create, Read, Update, Delete) operations, and connecting the application to MongoDB Atlas, a f... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-build-a-mern-stack-to-do-app/</link>
                <guid isPermaLink="false">67c74d6473daa61c95803cfc</guid>
                
                    <category>
                        <![CDATA[ MERN Stack ]]>
                    </category>
                
                    <category>
                        <![CDATA[ MongoDB ]]>
                    </category>
                
                    <category>
                        <![CDATA[ todoapp ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Casmir Onyekani ]]>
                </dc:creator>
                <pubDate>Tue, 04 Mar 2025 18:58:44 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1741102112733/3aa43545-c095-4a47-8787-130b470f6ce1.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>This guide will walk you through building a full-stack MERN To-Do application. It covers setting up the environment, writing code to demonstrate core CRUD (Create, Read, Update, Delete) operations, and connecting the application to MongoDB Atlas, a free cloud database.</p>
<p>Before diving into this article, I recommend that you have a foundational understanding of HTML, CSS, and JavaScript, as well as some knowledge of frontend and backend frameworks and libraries.</p>
<p>My primary focus will be on functionality, allowing you to customize the design as you see fit. The commands I’ll use here are tailored for Windows, so if you're using Linux, macOS, or Ubuntu, you may need to adjust them accordingly.</p>
<p>By the end of this guide, you'll have a fully functional To-Do app up and running on your system.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-introduction-to-the-mern-stack">Introduction to the MERN Stack</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-set-up-your-development-environment">How to Set Up Your Development environment</a></p>
<ul>
<li><a class="post-section-overview" href="#heading-install-nodejs-and-npm-node-package-manager">Install Node.js and npm - Node Package Manager</a></li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-set-up-a-new-mern-project">How to Set Up a New MERN Project</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-frontend-setup">Frontend Setup</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-build-the-to-do-app-ui">Build the To-Do App UI</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-displaying-your-tasks-in-the-ui">Displaying your tasks in the UI</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-give-your-app-customized-styling">Give Your App Customized Styling</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-backend-setup">Backend Setup</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-set-up-mongodb-atlas">Set Up MongoDB Atlas</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-run-the-application">Run the Application</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h2 id="heading-introduction-to-the-mern-stack">Introduction to the MERN Stack</h2>
<p>The MERN stack is a popular JavaScript stack for building modern web applications. It consists of:</p>
<ul>
<li><p><strong>MongoDB</strong>: A NoSQL database for storing data.</p>
</li>
<li><p><strong>Express.js</strong>: A backend framework for building APIs.</p>
</li>
<li><p><strong>React (UI library) + Vite (build tool) + TypeScript (typed JavaScript)</strong>: A modern frontend stack for building scalable and maintainable user interfaces.</p>
</li>
<li><p><strong>Node.js</strong>: A runtime environment for executing JavaScript on the server.</p>
</li>
</ul>
<h2 id="heading-how-to-set-up-your-development-environment">How to Set Up Your Development environment</h2>
<h3 id="heading-install-nodejs-and-npm-node-package-manager">Install Node.js and npm (Node Package Manager)</h3>
<p>Instead of installing Node.js and npm in your project folder, I advise you to install them in your system's root directory so that you can use them in any project, not just this one.</p>
<p>First, download and install Node.js (which includes npm) from the <a target="_blank" href="https://nodejs.org/en">official website</a> if you don’t have it already.</p>
<p>After installation, open your command line (I am using Git Bash) and verify the installation by running the following commands:</p>
<pre><code class="lang-bash">node -v
npm -v
</code></pre>
<p>You should see the installed versions of Node.js and npm if correctly installed.</p>
<h2 id="heading-how-to-set-up-a-new-mern-project">How to Set Up a New MERN Project</h2>
<p>Create a project folder and open your code editor by running these commands:</p>
<pre><code class="lang-bash">mkdir mern-todo-app
<span class="hljs-built_in">cd</span> mern-todo-app
code .
</code></pre>
<p>The command <code>code .</code> automatically opens VS Code. If it doesn’t, open VS Code manually and navigate to your <code>mern-todo-app</code> folder.</p>
<h3 id="heading-frontend-setup">Frontend Setup</h3>
<h4 id="heading-set-up-vite-with-react-and-typescript">Set Up Vite with React and TypeScript</h4>
<p>Make sure you are in your project root directory (<code>mern-todo-app</code>), then run the following command:</p>
<pre><code class="lang-bash">npm create vite@latest frontend --template react-ts
</code></pre>
<p>This command will create a TypeScript-based React frontend inside the <code>frontend</code> folder within your <code>mern-todo-app</code> directory.</p>
<h4 id="heading-install-axios-for-making-api-requests">Install Axios for Making API Requests</h4>
<p>Axios is a popular JavaScript library used to make HTTP requests from the frontend to a backend API. It simplifies sending GET, POST, PUT, and DELETE requests and handling responses.</p>
<p>To install Axios, run the following command:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> frontend
npm install axios
</code></pre>
<h3 id="heading-build-the-to-do-app-ui">Build the To-Do App UI</h3>
<p>Inside the <code>src</code> folder, create an <code>App.tsx</code> file if it doesn’t already exist, and add the below code. It’s a lot, but don’t worry – I’ll break it down bit by bit afterwards:</p>
<p><code>frontend/src/App.tsx</code>:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// BLOCK 1: Importing Dependencies</span>
<span class="hljs-keyword">import</span> React, { useState, useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">"axios"</span>;
<span class="hljs-keyword">import</span> TodoList <span class="hljs-keyword">from</span> <span class="hljs-string">"./components/TodoList.tsx"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"./App.css"</span>;

<span class="hljs-comment">// BLOCK 2: Defining Task Interface</span>
interface Task {
  <span class="hljs-attr">_id</span>: string;
  title: string;
  completed: boolean;
}

<span class="hljs-comment">// BLOCK 3: Setting Up State Variables</span>
<span class="hljs-keyword">const</span> App: React.FC = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-comment">// State for tasks, new task text, and editing controls</span>
  <span class="hljs-keyword">const</span> [tasks, setTasks] = useState&lt;Task[]&gt;([]);
  <span class="hljs-keyword">const</span> [task, setTask] = useState&lt;string&gt;(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> [editingTaskId, setEditingTaskId] = useState&lt;string | <span class="hljs-literal">null</span>&gt;(<span class="hljs-literal">null</span>);
  <span class="hljs-keyword">const</span> [editingTitle, setEditingTitle] = useState&lt;string&gt;(<span class="hljs-string">""</span>);

  <span class="hljs-comment">// BLOCK 4: Fetch tasks from the backend on component mount</span>
  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> fetchTasks = <span class="hljs-keyword">async</span> () =&gt; {
      <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> axios.get&lt;Task[]&gt;(<span class="hljs-string">`http://localhost:5000/api/tasks`</span>);
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Fetched tasks:"</span>, response.data); <span class="hljs-comment">// Debugging log</span>
        setTasks(response.data);
      } <span class="hljs-keyword">catch</span> (error) {
        <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Error fetching tasks:"</span>, error);
      }
    };
    fetchTasks();
  }, []);

  <span class="hljs-comment">// BLOCK 5: Adding a Task</span>
  <span class="hljs-keyword">const</span> addTask = <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">if</span> (!task) <span class="hljs-keyword">return</span>;

    <span class="hljs-keyword">try</span> {
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Adding task:"</span>, task); <span class="hljs-comment">// Debugging log</span>
      <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> axios.post&lt;Task&gt;(
        <span class="hljs-string">`http://localhost:5000/api/tasks`</span>,
        { <span class="hljs-attr">title</span>: task },
        { <span class="hljs-attr">headers</span>: { <span class="hljs-string">"Content-Type"</span>: <span class="hljs-string">"application/json"</span> } }
      );
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Task added response:"</span>, response.data);
      setTasks([...tasks, response.data]);
      setTask(<span class="hljs-string">""</span>);
    } <span class="hljs-keyword">catch</span> (error) {
      <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Error adding task:"</span>, error);
    }
  };

  <span class="hljs-comment">// BLOCK 6: Delete a task</span>
  <span class="hljs-keyword">const</span> deleteTask = <span class="hljs-keyword">async</span> (id: string) =&gt; {
    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">await</span> axios.delete(<span class="hljs-string">`http://localhost:5000/api/tasks/<span class="hljs-subst">${id}</span>`</span>);
      setTasks(tasks.filter(<span class="hljs-function">(<span class="hljs-params">t</span>) =&gt;</span> t._id !== id));
    } <span class="hljs-keyword">catch</span> (error) {
      <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Error deleting task:"</span>, error);
    }
  };

  <span class="hljs-comment">// BLOCK 7: Updating a Task</span>
  <span class="hljs-keyword">const</span> updateTask = <span class="hljs-keyword">async</span> (id: string, <span class="hljs-attr">updatedTask</span>: Partial&lt;Task&gt;) =&gt; {
    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> axios.put(
        <span class="hljs-string">`http://localhost:5000/api/tasks/<span class="hljs-subst">${id}</span>`</span>,
        updatedTask,
        { <span class="hljs-attr">headers</span>: { <span class="hljs-string">"Content-Type"</span>: <span class="hljs-string">"application/json"</span> } }
      );

      setTasks(
        tasks.map(<span class="hljs-function">(<span class="hljs-params">task</span>) =&gt;</span>
          task._id === id ? { ...task, ...response.data } : task
        )
      );
      setEditingTaskId(<span class="hljs-literal">null</span>);
      setEditingTitle(<span class="hljs-string">""</span>);
    } <span class="hljs-keyword">catch</span> (error) {
      <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Error updating task:"</span>, error);
    }
  };

  <span class="hljs-comment">// BLOCK 8: Handling Edits</span>
  <span class="hljs-keyword">const</span> startEditing = <span class="hljs-function">(<span class="hljs-params">id: string</span>) =&gt;</span> {
    setEditingTaskId(id);
  };

  <span class="hljs-comment">// Handle title change during editing</span>
  <span class="hljs-keyword">const</span> handleEditChange = <span class="hljs-function">(<span class="hljs-params">e: React.ChangeEvent&lt;HTMLInputElement&gt;</span>) =&gt;</span> {
    setEditingTitle(e.target.value);
  };

  <span class="hljs-comment">// BLOCK 9: Render the app</span>
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"App"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Todo App<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
          <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span>
          <span class="hljs-attr">value</span>=<span class="hljs-string">{task}</span>
          <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setTask(e.target.value)}
        /&gt;
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{addTask}</span>&gt;</span>Add Task<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">TodoList</span>
        <span class="hljs-attr">tasks</span>=<span class="hljs-string">{tasks}</span>
        <span class="hljs-attr">deleteTask</span>=<span class="hljs-string">{deleteTask}</span>
        <span class="hljs-attr">updateTask</span>=<span class="hljs-string">{updateTask}</span>
        <span class="hljs-attr">editingTitle</span>=<span class="hljs-string">{editingTitle}</span>
        <span class="hljs-attr">setEditingTitle</span>=<span class="hljs-string">{setEditingTitle}</span>
        <span class="hljs-attr">editingTaskId</span>=<span class="hljs-string">{editingTaskId}</span>
        <span class="hljs-attr">setEditingTaskId</span>=<span class="hljs-string">{setEditingTaskId}</span>
        <span class="hljs-attr">startEditing</span>=<span class="hljs-string">{startEditing}</span>
        <span class="hljs-attr">handleEditChange</span>=<span class="hljs-string">{handleEditChange}</span>
      /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
};

<span class="hljs-comment">// BLOCK 10: Exporting the Component</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>Here’s a block-by-block breakdown of the code above:</p>
<p><strong>BLOCK 1:</strong> Importing dependencies</p>
<ul>
<li><p><code>React, { useState, useEffect }</code>: Manages component state and side effects.</p>
</li>
<li><p><code>axios</code>: Handles API requests.</p>
</li>
<li><p><code>TodoList.tsx</code>: A child component to display and manage tasks.</p>
</li>
<li><p><code>App.css</code>: Styles the app.</p>
</li>
</ul>
<p><strong>BLOCK 2:</strong> Defining the task interface</p>
<ul>
<li>Defines the structure of a task (<code>_id</code>, <code>title</code>, <code>completed</code>).</li>
</ul>
<p><strong>BLOCK 3:</strong> Setting up state variables</p>
<ul>
<li><p><code>tasks</code>: Stores the list of tasks.</p>
</li>
<li><p><code>task</code>: Holds input for new tasks.</p>
</li>
<li><p><code>editingTaskId</code>: Tracks the task being edited.</p>
</li>
<li><p><code>editingTitle</code>: Stores the updated title while editing.</p>
</li>
</ul>
<p><strong>BLOCK 4:</strong> Fetching tasks from the backend (<code>useEffect</code>)</p>
<ul>
<li><p>Runs once when the app loads.</p>
</li>
<li><p>Calls the API (<code>GET /api/tasks</code>) to get tasks and updates <code>tasks</code>.</p>
</li>
<li><p>Error handling**:** Logs an error message if the fetching request fails</p>
</li>
</ul>
<p><strong>BLOCK 5:</strong> Adding a task</p>
<ul>
<li><p>Sends a <code>POST</code> request to add a new task.</p>
</li>
<li><p>Updates <code>tasks</code> with the new task.</p>
</li>
<li><p>Error handling**:** Logs an error message if the adding task request fails</p>
</li>
</ul>
<p><strong>BLOCK 6:</strong> Deleting a task</p>
<ul>
<li><p>Sends a <code>DELETE</code> request to remove a task.</p>
</li>
<li><p>Updates <code>tasks</code> by filtering out the deleted task.</p>
</li>
<li><p>Error handling**:** Logs an error message if the deleting task request fails</p>
</li>
</ul>
<p><strong>BLOCK 7:</strong> Updating a task</p>
<ul>
<li><p>Sends a <code>PUT</code> request to update a task’s title.</p>
</li>
<li><p>Updates <code>tasks</code> with the new title.</p>
</li>
<li><p>Error handling**:** Logs an error message if the update request fails</p>
</li>
</ul>
<p><strong>BLOCK 8:</strong> Handling edits</p>
<ul>
<li><p><code>startEditing(id)</code>: Sets a task into edit mode.</p>
</li>
<li><p><code>handleEditChange(e)</code>: Updates the editing input.</p>
</li>
</ul>
<p><strong>BLOCK 9:</strong> Rendering the UI</p>
<ul>
<li><p>Displays an input field and button to add tasks.</p>
</li>
<li><p>Passes task data and functions (<code>deleteTask</code>, <code>updateTask</code>, etc.) to <code>TodoList.tsx</code>.</p>
</li>
</ul>
<p><strong>BLOCK 10:</strong> Exporting the component</p>
<ul>
<li><code>export default App;</code>: Makes <code>App</code> usable in other files.</li>
</ul>
<h3 id="heading-displaying-your-tasks-in-the-ui">Displaying your tasks in the UI</h3>
<p>Inside the <code>src</code> folder, create a new folder named <code>components</code>. Then add a <code>TodoList.tsx</code> file inside it with the below code.</p>
<p><code>src/components/TodoList.tsx</code>:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// BLOCK 1: Importing Dependencies</span>
<span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-comment">// BLOCK 2: Defining Interfaces</span>
interface Task {
  <span class="hljs-attr">_id</span>: string; <span class="hljs-comment">// Unique ID for the task</span>
  title: string; <span class="hljs-comment">// Task name</span>
  completed: boolean; <span class="hljs-comment">// True if done, False if not</span>
}

interface TodoListProps {
  <span class="hljs-attr">tasks</span>: Task[];
  deleteTask: <span class="hljs-function">(<span class="hljs-params">id: string</span>) =&gt;</span> <span class="hljs-keyword">void</span>;
  updateTask: <span class="hljs-function">(<span class="hljs-params">id: string, updatedTask: Partial&lt;Task&gt;</span>) =&gt;</span> <span class="hljs-keyword">void</span>;
  editingTitle: string;
  setEditingTitle: <span class="hljs-function">(<span class="hljs-params">title: string</span>) =&gt;</span> <span class="hljs-keyword">void</span>;
  editingTaskId: string | <span class="hljs-literal">null</span>;
  setEditingTaskId: <span class="hljs-function">(<span class="hljs-params">id: string | <span class="hljs-literal">null</span></span>) =&gt;</span> <span class="hljs-keyword">void</span>;
  startEditing: <span class="hljs-function">(<span class="hljs-params">id: string</span>) =&gt;</span> <span class="hljs-keyword">void</span>;
  handleEditChange: <span class="hljs-function">(<span class="hljs-params">e: React.ChangeEvent&lt;HTMLInputElement&gt;</span>) =&gt;</span> <span class="hljs-keyword">void</span>;
}

<span class="hljs-comment">// BLOCK 3: Declares the TodoList Component</span>
<span class="hljs-keyword">const</span> TodoList: React.FC&lt;TodoListProps&gt; = <span class="hljs-function">(<span class="hljs-params">{
  tasks,
  deleteTask,
  updateTask,
  editingTitle,
  setEditingTitle,
  editingTaskId,
  setEditingTaskId,
  startEditing,
  handleEditChange,
}</span>) =&gt;</span> {

  <span class="hljs-comment">// BLOCK 4: Rendering the Task List and handling task actions</span>
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
      {tasks.map((task) =&gt; (
        <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{task._id}</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
            <span class="hljs-attr">type</span>=<span class="hljs-string">"checkbox"</span>
            <span class="hljs-attr">checked</span>=<span class="hljs-string">{task.completed}</span>
            <span class="hljs-attr">onChange</span>=<span class="hljs-string">{()</span> =&gt;</span> updateTask(task._id, { completed: !task.completed })}
          /&gt;
          {editingTaskId === task._id ? (
            <span class="hljs-tag">&lt;&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">{editingTitle}</span> <span class="hljs-attr">onChange</span>=<span class="hljs-string">{handleEditChange}</span> /&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
                <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> {
                  updateTask(task._id, { title: editingTitle });
                  setEditingTaskId(null);
                }}
              &gt;
                Save
              <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
            <span class="hljs-tag">&lt;/&gt;</span>
          ) : (
            <span class="hljs-tag">&lt;&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">textDecoration:</span> <span class="hljs-attr">task.completed</span> ? "<span class="hljs-attr">line-through</span>" <span class="hljs-attr">:</span> "<span class="hljs-attr">none</span>" }}&gt;</span>
                {task.title}
              <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>

              <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> deleteTask(task._id)}&gt;Delete<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
                  <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> {
                    startEditing(task._id);
                    setEditingTitle(task.title);
                  }}
                &gt;
                  Edit
                <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;/&gt;</span></span>
          )}
        &lt;/li&gt;
      ))}
    &lt;/ul&gt;
  );
};

<span class="hljs-comment">// BLOCK 5: Exporting the Component</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> TodoList;
</code></pre>
<p>Here’s a block-by-block breakdown of the code above:</p>
<p><strong>BLOCK 1:</strong> Importing dependencies</p>
<ul>
<li>React: Enables functional component creation.</li>
</ul>
<p><strong>BLOCK 2:</strong> Defining interfaces</p>
<ul>
<li><p>Task interface: Defines <code>_id</code>, <code>title</code>, and <code>completed</code> properties.</p>
</li>
<li><p>TodoListProps interface: Defines props passed to the <code>TodoList</code> component</p>
</li>
</ul>
<p><strong>BLOCK 3</strong>: Declares the <code>TodoList</code> component</p>
<ul>
<li><p>Defines a functional React component (<code>TodoList</code>) using TypeScript (<code>React.FC&lt;TodoListProps&gt;</code>).</p>
</li>
<li><p>Extracts the listed props from <code>TodoListProps</code> and prepares the component for rendering.</p>
</li>
</ul>
<p><strong>BLOCK 4</strong>: Rendering the Task List and handling task actions</p>
<ul>
<li><p>Maps through <code>tasks</code> to display each task inside a <code>&lt;ul&gt;</code>.</p>
</li>
<li><p>Checkbox toggles <code>completed</code> status using <code>updateTask()</code>.</p>
</li>
<li><p>Conditional rendering:</p>
<ul>
<li><p>If a task is being edited, an input field appears for editing.</p>
</li>
<li><p>Otherwise, the task title is displayed with a strikethrough if completed</p>
</li>
</ul>
</li>
<li><p>Save button: Updates the task title using <code>updateTask()</code>, then exits edit mode.</p>
</li>
<li><p>Delete button: Calls <code>deleteTask()</code> to remove a task.</p>
</li>
<li><p>Edit button: Enables edit mode, setting <code>editingTaskId</code> and <code>editingTitle</code>.</p>
</li>
</ul>
<p><strong>BLOCK 5</strong>: Exporting the component</p>
<ul>
<li>Makes <code>TodoList</code> available for use in other components.</li>
</ul>
<h3 id="heading-give-your-app-customized-styling">Give Your App Customized Styling</h3>
<p>Inside your <code>src</code> folder, create <code>App.css</code> if it doesn’t exist and replace the content with your desired styling. Let’s give the frontend a finishing touch.</p>
<p><code>src/App.css</code>:</p>
<pre><code class="lang-css"><span class="hljs-comment">/* Center the app in the middle of the screen */</span>
<span class="hljs-selector-tag">html</span>, <span class="hljs-selector-tag">body</span> {
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">justify-content</span>: center;
  <span class="hljs-attribute">align-items</span>: center;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">100vh</span>;
  <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span>;
  <span class="hljs-attribute">font-family</span>: Arial, sans-serif;
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#f4f4f4</span>; <span class="hljs-comment">/* Light gray background */</span>
  <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
  <span class="hljs-attribute">overflow-x</span>: hidden; <span class="hljs-comment">/* Prevent horizontal scrolling */</span>
}

<span class="hljs-comment">/* Style the main app container */</span>
<span class="hljs-selector-class">.App</span> {
  <span class="hljs-attribute">text-align</span>: center;
  <span class="hljs-attribute">background</span>: white;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">20px</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">10px</span>; <span class="hljs-comment">/* Rounded corners */</span>
  <span class="hljs-attribute">box-shadow</span>: <span class="hljs-number">0</span> <span class="hljs-number">0</span> <span class="hljs-number">10px</span> <span class="hljs-built_in">rgba</span>(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0.1</span>); <span class="hljs-comment">/* Light shadow effect */</span>
  <span class="hljs-attribute">width</span>: <span class="hljs-number">90%</span>; <span class="hljs-comment">/* Make it flexible */</span>
  <span class="hljs-attribute">max-width</span>: <span class="hljs-number">350px</span>; <span class="hljs-comment">/* Prevent exceeding max size */</span>
  <span class="hljs-attribute">box-sizing</span>: border-box;
}

<span class="hljs-comment">/* Add spacing below the title */</span>
<span class="hljs-selector-tag">h1</span> {
  <span class="hljs-attribute">margin-bottom</span>: <span class="hljs-number">20px</span>;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">24px</span>;
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#333</span>;
}

<span class="hljs-comment">/* Style input fields */</span>
<span class="hljs-selector-tag">input</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>; <span class="hljs-comment">/* Full width */</span>
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">8px</span>;
  <span class="hljs-attribute">margin-bottom</span>: <span class="hljs-number">10px</span>;
  <span class="hljs-attribute">border</span>: <span class="hljs-number">1px</span> solid <span class="hljs-number">#ccc</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">5px</span>;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">16px</span>;
  <span class="hljs-attribute">box-sizing</span>: border-box;
}

<span class="hljs-comment">/* Style buttons */</span>
<span class="hljs-selector-tag">button</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>; <span class="hljs-comment">/* Make buttons full width */</span>
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">10px</span>;
  <span class="hljs-attribute">margin-top</span>: <span class="hljs-number">5px</span>;
  <span class="hljs-attribute">border</span>: none;
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#007bff</span>; <span class="hljs-comment">/* Blue background */</span>
  <span class="hljs-attribute">color</span>: white;
  <span class="hljs-attribute">cursor</span>: pointer;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">5px</span>;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">14px</span>;
  <span class="hljs-attribute">transition</span>: background-color <span class="hljs-number">0.3s</span> ease-in-out;
}

<span class="hljs-comment">/* Change button color when hovered */</span>
<span class="hljs-selector-tag">button</span><span class="hljs-selector-pseudo">:hover</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#0056b3</span>;
}

<span class="hljs-comment">/* Remove default list styles */</span>
<span class="hljs-selector-tag">ul</span> {
  <span class="hljs-attribute">list-style</span>: none;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">0</span>;
  <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span>;
}

<span class="hljs-comment">/* Style list items */</span>
<span class="hljs-selector-tag">li</span> {
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">align-items</span>: center;
  <span class="hljs-attribute">justify-content</span>: space-between;
  <span class="hljs-attribute">background</span>: <span class="hljs-number">#fff</span>;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">10px</span>;
  <span class="hljs-attribute">margin</span>: <span class="hljs-number">5px</span> <span class="hljs-number">0</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">5px</span>;
  <span class="hljs-attribute">box-shadow</span>: <span class="hljs-number">0</span> <span class="hljs-number">2px</span> <span class="hljs-number">5px</span> <span class="hljs-built_in">rgba</span>(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0.1</span>); <span class="hljs-comment">/* Add a subtle shadow */</span>
  <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
  <span class="hljs-attribute">box-sizing</span>: border-box;
}

<span class="hljs-comment">/* Allow task text to take available space */</span>
<span class="hljs-selector-tag">span</span> {
  <span class="hljs-attribute">flex</span>: <span class="hljs-number">1</span>;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">16px</span>;
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#333</span>;
}

<span class="hljs-comment">/* Style completed tasks */</span>
<span class="hljs-selector-tag">span</span><span class="hljs-selector-class">.completed</span> {
  <span class="hljs-attribute">text-decoration</span>: line-through;
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#888</span>;
}

<span class="hljs-comment">/* Adjust the width of input fields inside the list */</span>
<span class="hljs-selector-tag">input</span><span class="hljs-selector-attr">[type=<span class="hljs-string">"text"</span>]</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">70%</span>;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">8px</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">5px</span>;
  <span class="hljs-attribute">border</span>: <span class="hljs-number">1px</span> solid <span class="hljs-number">#ccc</span>;
}

<span class="hljs-comment">/* Style the checkbox */</span>
<span class="hljs-selector-tag">input</span><span class="hljs-selector-attr">[type=<span class="hljs-string">"checkbox"</span>]</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">18px</span>;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">18px</span>;
  <span class="hljs-attribute">cursor</span>: pointer;
  <span class="hljs-attribute">accent-color</span>: <span class="hljs-number">#007bff</span>; <span class="hljs-comment">/* Blue checkbox to match buttons */</span>
  <span class="hljs-attribute">margin-right</span>: <span class="hljs-number">10px</span>;
}

<span class="hljs-comment">/* Styling for editing mode */</span>
<span class="hljs-selector-class">.editing-container</span> {
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">align-items</span>: center;
  <span class="hljs-attribute">gap</span>: <span class="hljs-number">10px</span>;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
}

<span class="hljs-comment">/* Responsive styling for smaller screens */</span>
<span class="hljs-keyword">@media</span> (<span class="hljs-attribute">max-width:</span> <span class="hljs-number">400px</span>) {
  <span class="hljs-selector-class">.App</span> {
    <span class="hljs-attribute">width</span>: <span class="hljs-number">95%</span>;
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">15px</span>;
    <span class="hljs-attribute">max-width</span>: none; <span class="hljs-comment">/* Remove fixed width restriction */</span>
  }

  <span class="hljs-selector-tag">li</span> {
    <span class="hljs-attribute">flex-direction</span>: column;
    <span class="hljs-attribute">align-items</span>: flex-start;
  }

  <span class="hljs-selector-tag">input</span> {
    <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
  }

  <span class="hljs-selector-tag">button</span> {
    <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">10px</span>;
  }
}
</code></pre>
<p>Here’s what this CSS code does:</p>
<p>First, it centers the app (<code>html, body</code>):</p>
<ul>
<li><p>Uses <code>flexbox</code> to center the app vertically and horizontally.</p>
</li>
<li><p>Sets <code>height: 100vh</code> for full-screen height.</p>
</li>
<li><p>Prevents horizontal scrolling with <code>overflow-x: hidden</code>.</p>
</li>
</ul>
<p>Then it styles the main app container (<code>.App</code>):</p>
<ul>
<li><p>Adds a white background with rounded corners and a shadow.</p>
</li>
<li><p>Ensures responsiveness with <code>width: 90%</code> and <code>max-width: 350px</code>.</p>
</li>
</ul>
<p>Next, we handle typography and layout:</p>
<ul>
<li><p>Sets <code>Arial, sans-serif</code> as the font.</p>
</li>
<li><p>Adds spacing below the title (<code>h1</code>).</p>
</li>
<li><p>Ensures task text takes available space with <code>span { flex: 1; }</code>.</p>
</li>
</ul>
<p>Then we deal with input and button styling:</p>
<ul>
<li><p>Inputs are full-width, styled with padding, borders, and rounded corners.</p>
</li>
<li><p>Buttons are blue, full-width, with hover effects (<code>background-color: #0056b3</code>).</p>
</li>
</ul>
<p>And then task list styling <strong>(</strong><code>ul, li, span.completed</code>):</p>
<ul>
<li><p>Removes default list styles.</p>
</li>
<li><p>Each task (<code>li</code>) has a white background, padding, rounded corners, and a shadow.</p>
</li>
<li><p>Completed tasks are styled with a <code>line-through</code> and faded text color.</p>
</li>
</ul>
<p>Next, we handle checkbox and editing mode styling:</p>
<ul>
<li><p>Styled blue checkboxes (<code>accent-color: #007bff</code>).</p>
</li>
<li><p>Adds an <code>editing-container</code> with <code>display: flex;</code> for edit mode.</p>
</li>
</ul>
<p>And finally, we make the design responsive (<code>@media (max-width: 400px)</code>):</p>
<ul>
<li><p>Adjusts <code>.App</code> width and padding for small screens.</p>
</li>
<li><p>Stacks list items (<code>li</code>) vertically instead of side-by-side.</p>
</li>
</ul>
<h3 id="heading-backend-setup">Backend Setup</h3>
<p>In your VS Code terminal, make sure you are in your project root directory (inside <code>mern-todo-app</code>) and then create a folder called <code>backend</code>. Navigate to the <code>backend</code> folder and initialize <code>Node.js</code>:</p>
<pre><code class="lang-bash">mkdir backend
<span class="hljs-built_in">cd</span> backend
npm init -y
</code></pre>
<h4 id="heading-install-dependencies">Install Dependencies</h4>
<p>Still inside your <code>backend</code> folder, run this command:</p>
<pre><code class="lang-bash">npm install express mongoose dotenv cors
</code></pre>
<p>In this command,</p>
<ul>
<li><p><code>express</code> is a fast and minimal web framework for Node.js used to create server-side applications and APIs.</p>
</li>
<li><p><code>mongoose</code> is an Object Data Modeling (ODM) library for MongoDB, simplifying database interactions.</p>
</li>
<li><p><code>dotenv</code> loads environment variables from a <code>.env</code> file, keeping sensitive data secure.</p>
</li>
<li><p><code>cors</code> enables Cross-Origin Resource Sharing, allowing frontend applications to communicate with the backend across different domains.</p>
</li>
</ul>
<h4 id="heading-create-a-serverjs-file">Create a server.js File</h4>
<p>Inside your <code>backend</code> folder, create a file named <code>server.js</code> and enter the following code:</p>
<p><code>backend/server.js</code>:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// BLOCK 1: Importing Dependencies</span>
<span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">"express"</span>);
<span class="hljs-keyword">const</span> mongoose = <span class="hljs-built_in">require</span>(<span class="hljs-string">"mongoose"</span>);
<span class="hljs-keyword">const</span> cors = <span class="hljs-built_in">require</span>(<span class="hljs-string">"cors"</span>);
<span class="hljs-keyword">const</span> dotenv = <span class="hljs-built_in">require</span>(<span class="hljs-string">"dotenv"</span>);

<span class="hljs-comment">// BLOCK 2: Configuring the Express App</span>
dotenv.config();

<span class="hljs-keyword">const</span> app = express();

<span class="hljs-comment">// BLOCK 3: Setting Up Middleware</span>
app.use(cors());
app.use(express.json());

<span class="hljs-comment">// BLOCK 4: Connecting to MongoDB</span>
<span class="hljs-keyword">const</span> connectDB = <span class="hljs-keyword">async</span> () =&gt; {
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">await</span> mongoose.connect(process.env.MONGO_URI);
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"MongoDB Connected"</span>);
  } <span class="hljs-keyword">catch</span> (err) {
    <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"MongoDB Connection Failed:"</span>, err);
    process.exit(<span class="hljs-number">1</span>); <span class="hljs-comment">// Exit process with failure</span>
  }
};

<span class="hljs-comment">// Call the database connection function</span>
connectDB();

<span class="hljs-comment">// BLOCK 5: Defining Routes</span>
<span class="hljs-keyword">const</span> tasksRoutes = <span class="hljs-built_in">require</span>(<span class="hljs-string">"./routes/tasks"</span>);
app.use(<span class="hljs-string">"/api/tasks"</span>, tasksRoutes);

<span class="hljs-comment">// BLOCK 6: Starting the Server</span>
<span class="hljs-keyword">const</span> PORT = process.env.PORT || <span class="hljs-number">5000</span>;
app.listen(PORT, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Server running on port <span class="hljs-subst">${PORT}</span>`</span>);
});
</code></pre>
<p>Here’s a block-by-block breakdown of the code above:</p>
<p><strong>BLOCK 1</strong>: Importing dependencies</p>
<ul>
<li><p>express**:** Creates the server.</p>
</li>
<li><p>mongoose**:** Connects to MongoDB.</p>
</li>
<li><p>cors**:** Enables cross-origin requests.</p>
</li>
<li><p>dotenv**:** Loads environment variables.</p>
</li>
</ul>
<p><strong>BLOCK 2</strong>: Configuring the Express app</p>
<ul>
<li><p>Loads environment variables using <code>dotenv.config()</code>.</p>
</li>
<li><p>Initializes <code>express()</code> to create an app instance.</p>
</li>
</ul>
<p><strong>BLOCK 3</strong>: Setting up middleware</p>
<ul>
<li><p>cors()<strong>:</strong> Allows API access from different origins.</p>
</li>
<li><p>express.json()<strong>:</strong> Parses incoming JSON requests.</p>
</li>
</ul>
<p><strong>BLOCK 4</strong>: Connecting to MongoDB</p>
<ul>
<li><p>Defines <code>connectDB()</code> to connect to MongoDB using <code>MONGO_URI</code>.</p>
</li>
<li><p>Logs success or failure and exits on error.</p>
</li>
</ul>
<p><strong>BLOCK 5</strong>: Defining routes</p>
<ul>
<li><p>Imports <code>tasksRoutes</code> from <code>./routes/tasks</code>.</p>
</li>
<li><p>Uses <code>/api/tasks</code> as the base route for task operations.</p>
</li>
</ul>
<p><strong>BLOCK 6</strong>: Starting the server</p>
<ul>
<li><p>Sets <code>PORT</code> from <code>.env</code> or defaults to <code>5000</code>.</p>
</li>
<li><p>Starts the server and logs the running port.</p>
</li>
</ul>
<h4 id="heading-define-task-model">Define Task Model</h4>
<p>In your <code>backend</code> folder, create a <code>model</code> folder. Inside <code>model</code>, create a file named <code>Task.js</code> and add the following code:</p>
<p><code>backend/model/Task.js</code>:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// BLOCK 1: Importing Mongoose</span>
<span class="hljs-keyword">const</span> mongoose = <span class="hljs-built_in">require</span>(<span class="hljs-string">"mongoose"</span>);

<span class="hljs-comment">// BLOCK 2: Defining Task Schema</span>
<span class="hljs-keyword">const</span> TaskSchema = <span class="hljs-keyword">new</span> mongoose.Schema({
    <span class="hljs-attr">title</span>: { <span class="hljs-attr">type</span>: <span class="hljs-built_in">String</span>, <span class="hljs-attr">required</span>: <span class="hljs-literal">true</span> },
    <span class="hljs-attr">completed</span>: { <span class="hljs-attr">type</span>: <span class="hljs-built_in">Boolean</span>, <span class="hljs-attr">default</span>: <span class="hljs-literal">false</span> },
});

<span class="hljs-comment">// BLOCK 3: Creating and Exporting the Model</span>
<span class="hljs-built_in">module</span>.exports = mongoose.model(<span class="hljs-string">"Task"</span>, TaskSchema);
</code></pre>
<p>Here’s a block-by-block breakdown of the code above:</p>
<p><strong>BLOCK 1</strong>: Importing Mongoose</p>
<ul>
<li><code>mongoose</code>: Used to define the schema and interact with MongoDB.</li>
</ul>
<p><strong>BLOCK 2</strong>: Defining the task schema</p>
<ul>
<li><p><code>title</code>: A required string field for the task title.</p>
</li>
<li><p><code>completed</code>: A boolean field indicating task status (default: <code>false</code>).</p>
</li>
</ul>
<p><strong>BLOCK 3</strong>: Creating and exporting the model</p>
<ul>
<li><p>Creates a Mongoose model named <code>"Task"</code> based on <code>TaskSchema</code>.</p>
</li>
<li><p>Exports the model for use in other parts of the application</p>
</li>
</ul>
<h4 id="heading-define-routes">Define Routes</h4>
<p>In your <code>backend</code> folder, create a <code>routes</code> folder. Inside <code>routes</code>, create a file named <code>tasks.js</code> and add the following code:</p>
<p><code>backend/routes/tasks.js</code>:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// BOCK 1: Import dependencies</span>
<span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">"express"</span>);
<span class="hljs-keyword">const</span> Task = <span class="hljs-built_in">require</span>(<span class="hljs-string">"../models/Task"</span>);

<span class="hljs-keyword">const</span> router = express.Router();

<span class="hljs-comment">// BLOCK 2: GET all tasks</span>
router.get(<span class="hljs-string">"/"</span>, <span class="hljs-keyword">async</span> (req, res) =&gt; {
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> tasks = <span class="hljs-keyword">await</span> Task.find();
    res.json(tasks);
  } <span class="hljs-keyword">catch</span> (err) {
    res.status(<span class="hljs-number">500</span>).json({ <span class="hljs-attr">error</span>: err.message });
  }
});

<span class="hljs-comment">// BLOCK 3: POST a new task</span>
router.post(<span class="hljs-string">"/"</span>, <span class="hljs-keyword">async</span> (req, res) =&gt; {
  <span class="hljs-keyword">const</span> { title } = req.body;
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Received title:"</span>, title); <span class="hljs-comment">// Debugging log</span>

  <span class="hljs-keyword">if</span> (!title) {
    <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">400</span>).json({ <span class="hljs-attr">error</span>: <span class="hljs-string">"Task title is required"</span> });
  }

  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> newTask = <span class="hljs-keyword">new</span> Task({ title });
    <span class="hljs-keyword">await</span> newTask.save();
    res.status(<span class="hljs-number">201</span>).json(newTask);
  } <span class="hljs-keyword">catch</span> (err) {
    <span class="hljs-built_in">console</span>.error(err.message);
    res.status(<span class="hljs-number">500</span>).json({ <span class="hljs-attr">error</span>: err.message });
  }
});

<span class="hljs-comment">// BLOCK 4: DELETE a task</span>
router.delete(<span class="hljs-string">"/:id"</span>, <span class="hljs-keyword">async</span> (req, res) =&gt; {
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> { id } = req.params;
    <span class="hljs-keyword">await</span> Task.findByIdAndDelete(id);
    res.json({ <span class="hljs-attr">message</span>: <span class="hljs-string">"Task deleted"</span> });
  } <span class="hljs-keyword">catch</span> (err) {
    res.status(<span class="hljs-number">500</span>).json({ <span class="hljs-attr">error</span>: err.message });
  }
});

<span class="hljs-comment">// BLOCK 5: UPDATE a task</span>
router.put(<span class="hljs-string">"/:id"</span>, <span class="hljs-keyword">async</span> (req, res) =&gt; {
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> { id } = req.params;

    <span class="hljs-keyword">const</span> updatedTask = <span class="hljs-keyword">await</span> Task.findByIdAndUpdate(
      id,
      req.body,
      { <span class="hljs-attr">new</span>: <span class="hljs-literal">true</span> } <span class="hljs-comment">// Return the updated task</span>
    );
    res.json(updatedTask);
  } <span class="hljs-keyword">catch</span> (error) {
    res.status(<span class="hljs-number">500</span>).json({ <span class="hljs-attr">error</span>: <span class="hljs-string">"Error updating task"</span> });
  }
});

<span class="hljs-comment">// BLOCK 6: Export the router</span>
<span class="hljs-built_in">module</span>.exports = router;
</code></pre>
<p>Here’s a block-by-block breakdown of the code above:</p>
<p><strong>BLOCK 1</strong>: Import dependencies</p>
<ul>
<li><p>express: Handles routing.</p>
</li>
<li><p>Task: Imports the Task model.</p>
</li>
<li><p>express.Router(): Creates a router for task-related routes.</p>
</li>
</ul>
<p><strong>BLOCK 2</strong>: GET all tasks</p>
<ul>
<li><p>Fetches all tasks from the database.</p>
</li>
<li><p>Sends the tasks as a JSON response.</p>
</li>
<li><p>Handles errors with a 500 status.</p>
</li>
</ul>
<p><strong>BLOCK 3</strong>: POST a new task</p>
<ul>
<li><p>Extracts <code>title</code> from the request body.</p>
</li>
<li><p>Logs the received title for debugging.</p>
</li>
<li><p>Validates the title (returns 400 if missing).</p>
</li>
<li><p>Saves the task to the database and returns it.</p>
</li>
</ul>
<p><strong>BLOCK 4</strong>: DELETE a task</p>
<ul>
<li><p>Extracts <code>id</code> from the request params.</p>
</li>
<li><p>Deletes the task from the database.</p>
</li>
<li><p>Returns a success message.</p>
</li>
</ul>
<p><strong>BLOCK 5</strong>: UPDATE a task</p>
<ul>
<li><p>Extracts <code>id</code> from the request params.</p>
</li>
<li><p>Updates the task using request body data.</p>
</li>
<li><p>Returns the updated task.</p>
</li>
</ul>
<p><strong>BLOCK 6</strong>: Export the router</p>
<ul>
<li>Exports <code>router</code> for use in other parts of the app.</li>
</ul>
<p>This Express.js router handles CRUD operations for a <code>Task</code> model using MongoDB. It defines routes to get all tasks, add a new task, delete a task by ID, and update a task's title by ID. Error handling ensures proper responses for missing data or server issues.</p>
<h4 id="heading-create-a-env-file">Create a .env file</h4>
<p>In your backend folder, create a <code>.env</code> file and add the following:</p>
<p><code>backend/.env</code>:</p>
<pre><code class="lang-javascript">MONGO_URI=your_mongodb_atlas_uri
</code></pre>
<h3 id="heading-set-up-mongodb-atlas">Set Up MongoDB Atlas</h3>
<p>MongoDB Atlas is a cloud-based MongoDB service. We'll use the free tier for this project.</p>
<p>To get started, go to <a target="_blank" href="https://www.mongodb.com/products/platform/atlas-database">MongoDB Atlas</a> and create an account or log in.</p>
<p>Follow the steps to create a free cluster. Once the cluster is created, click Connect and follow the instructions to:</p>
<ul>
<li><p>Whitelist your IP address to allow MongoDB access using your environment variable.</p>
</li>
<li><p>Create a database user.</p>
</li>
<li><p>Get the connection string.</p>
</li>
</ul>
<p>Replace the <code>your_mongodb_atlas_uri</code> in <code>.env</code> file with your MongoDB Atlas connection string.</p>
<p>If you are still not comfortable with how to set up MongoDB atlas, read this: <a target="_blank" href="https://www.freecodecamp.org/news/get-started-with-mongodb-atlas/">MongoDB Atlas Tutorial – How to Get Started</a>.</p>
<h3 id="heading-run-the-application">Run the Application</h3>
<p>To run the application successfully using <code>npm run dev</code>, you need to install a dependency that will start both the frontend and backend simultaneously. You can do this using <a target="_blank" href="https://www.npmjs.com/package/concurrently">concurrently</a><strong>.</strong></p>
<p>Install concurrently:</p>
<p>Open your terminal, navigate to your project root directory (<code>mern-todo-app</code>), and run:</p>
<pre><code class="lang-bash">npm install concurrently
</code></pre>
<h4 id="heading-configure-packagejson">Configure <code>package.json</code>:</h4>
<p>After installing concurrently, ensure that you have a <code>package.json</code> file in your project root directory. If it doesn't exist, create one and add the following code:</p>
<p><code>mern-todo-app/package.json</code>:</p>
<pre><code class="lang-json">{
    <span class="hljs-attr">"name"</span>: <span class="hljs-string">"mern-todo-app"</span>,
    <span class="hljs-attr">"version"</span>: <span class="hljs-string">"1.0.0"</span>,
    <span class="hljs-attr">"private"</span>: <span class="hljs-literal">true</span>,
    <span class="hljs-attr">"scripts"</span>: {
        <span class="hljs-attr">"start"</span>: <span class="hljs-string">"cd backend &amp;&amp; npm start"</span>,
        <span class="hljs-attr">"client"</span>: <span class="hljs-string">"cd frontend &amp;&amp; npm run dev"</span>,
        <span class="hljs-attr">"dev"</span>: <span class="hljs-string">"concurrently \"npm run start\" \"npm run client\""</span>
    },
    <span class="hljs-attr">"dependencies"</span>: {
        <span class="hljs-attr">"concurrently"</span>: <span class="hljs-string">"^8.2.2"</span>
    }
}
</code></pre>
<p>This <code>package.json</code> file configures the application by defining:</p>
<ul>
<li><p>Project metadata (<code>name, version, private flag</code>).</p>
</li>
<li><p>Scripts (<code>start</code>, <code>client</code>, and <code>dev</code>) to start the backend, run the frontend, and execute both simultaneously.</p>
</li>
<li><p>Dependencies, including <code>concurrently</code>, which enables running multiple scripts in parallel.</p>
</li>
<li><p>The project is set to private to prevent accidental publishing.</p>
</li>
</ul>
<h4 id="heading-start-the-application">Start the Application</h4>
<p>Ensure everything is set up and saved, then run the following command from the project root:</p>
<pre><code class="lang-bash">npm run dev
</code></pre>
<p>If the application starts successfully, you should see messages like:</p>
<pre><code class="lang-nginx"><span class="hljs-attribute">Server</span> running <span class="hljs-literal">on</span> port <span class="hljs-number">5000</span>
MongoDB Connected
</code></pre>
<h4 id="heading-view-the-application">View the Application</h4>
<p>Open your browser and navigate to:</p>
<ul>
<li><p>Frontend (To-Do app interface)<strong>:</strong> <strong>http://localhost:5173</strong></p>
</li>
<li><p>Backend (Stored tasks in the database)<strong>:</strong> <strong>http://localhost:5000/api/tasks</strong></p>
</li>
</ul>
<p>Test the functionality by adding, editing, saving, deleting tasks, and checking off completed tasks to ensure everything works properly.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Congratulations! You have successfully built a MERN To-Do app. You can further enhance it by adding features such as time and date tracking, and deploying it to a cloud platform.</p>
<p>Feel free to copy the code or clone the <a target="_blank" href="https://github.com/nuelcas/mern-todo-app.git">GitHub</a> repository to add more functionalities and customize the styling to your preference. If you found this guide helpful, please consider sharing it and <a target="_blank" href="https://www.linkedin.com/in/casmir-onyekani/">connecting</a> with me!</p>
<p>For more learning resources:</p>
<ul>
<li><p><a target="_blank" href="https://react.dev/">React.js Docs</a></p>
</li>
<li><p><a target="_blank" href="https://www.typescriptlang.org/">TypeScript Docs</a></p>
</li>
<li><p><a target="_blank" href="https://vite.dev/">Vite Docs</a></p>
</li>
<li><p><a target="_blank" href="https://www.mongodb.com/docs/">MongoDB Docs</a></p>
</li>
<li><p><a target="_blank" href="https://nodejs.org/docs/latest/api/">Node.js Docs</a></p>
</li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
