<?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[ Danny - 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[ Danny - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Sun, 24 May 2026 22:24:01 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/author/DoableDanny/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ What is Polymorphism in Python? Explained with an Example ]]>
                </title>
                <description>
                    <![CDATA[ Polymorphism is an object-oriented programming (OOP) principle that helps you write high quality, flexible, maintainable, reusable, testable, and readable software. If you plan to work with object-oriented software, it is crucial to understand polymo... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/what-is-polymorphism-in-python-example/</link>
                <guid isPermaLink="false">67a4d16ab891dd1403996d28</guid>
                
                    <category>
                        <![CDATA[ Python ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Object Oriented Programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ oop ]]>
                    </category>
                
                    <category>
                        <![CDATA[ design patterns ]]>
                    </category>
                
                    <category>
                        <![CDATA[ software development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Danny ]]>
                </dc:creator>
                <pubDate>Thu, 06 Feb 2025 15:12:42 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1738335631634/ef8f79a0-73df-430c-b955-a5325ca22f04.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Polymorphism is an object-oriented programming (OOP) principle that helps you write high quality, flexible, maintainable, reusable, testable, and readable software. If you plan to work with object-oriented software, it is crucial to understand polymorphism.</p>
<h2 id="heading-what-is-polymorphism">What is Polymorphism?</h2>
<p>The word <em>polymorphism</em> is derived from Greek, and means "having multiple forms":</p>
<ul>
<li><p>Poly = many</p>
</li>
<li><p>Morph = forms</p>
</li>
</ul>
<p><strong>In programming, polymorphism is the ability of an object to take many forms</strong>.</p>
<p>The key advantage of polymorphism is that it allows us to write more <strong>generic</strong> and <strong>reusable</strong> code. Instead of writing separate logic for different classes, we define common behaviours in a parent class and let child classes override them as needed. This eliminates the need for excessive <code>if-else</code> checks, making the code more maintainable and extensible.</p>
<p>MVC frameworks like <a target="_blank" href="http://djangoproject.com/">Django</a> use polymorphism to make code more flexible. For example, Django supports different databases like SQLite, MySQL, and PostgreSQL. Normally, each database requires different code to interact with it, but Django provides a single database API that works with all of them. This means you can write the same code for database operations, no matter which database you use. So, if you start a project with SQLite and later switch to PostgreSQL, you won’t need to rewrite much of your code, thanks to polymorphism.</p>
<p>In this article, to make things easy to understand, I’ll show you a bad code example with no polymorphism. We’ll discuss the issues that this bad code causes, and then solve the issues by refactoring the code to use polymorphism.</p>
<p>(Btw, if you learn better by video, checkout my <a target="_blank" href="https://youtu.be/zuPg8_qsL7A">Polymorphism in Python</a> YouTube video.)</p>
<h2 id="heading-first-an-example-with-no-polymorphism">First, an example with no polymorphism:</h2>
<pre><code class="lang-python"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Car</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, brand, model, year, number_of_doors</span>):</span>
        self.brand = brand
        self.model = model
        self.year = year
        self.number_of_doors = number_of_doors

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">start</span>(<span class="hljs-params">self</span>):</span>
        print(<span class="hljs-string">"Car is starting."</span>)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">stop</span>(<span class="hljs-params">self</span>):</span>
        print(<span class="hljs-string">"Car is stopping."</span>)
</code></pre>
<pre><code class="lang-python"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Motorcycle</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, brand, model, year</span>):</span>
        self.brand = brand
        self.model = model
        self.year = year

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">start_bike</span>(<span class="hljs-params">self</span>):</span>
        print(<span class="hljs-string">"Motorcycle is starting."</span>)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">stop_bike</span>(<span class="hljs-params">self</span>):</span>
        print(<span class="hljs-string">"Motorcycle is stopping."</span>)
</code></pre>
<p>Let’s say that we want to create a list of vehicles, then loop through it and perform an inspection on each vehicle:</p>
<pre><code class="lang-python"><span class="hljs-comment"># Create list of vehicles to inspect</span>
vehicles = [
    Car(<span class="hljs-string">"Ford"</span>, <span class="hljs-string">"Focus"</span>, <span class="hljs-number">2008</span>, <span class="hljs-number">5</span>),
    Motorcycle(<span class="hljs-string">"Honda"</span>, <span class="hljs-string">"Scoopy"</span>, <span class="hljs-number">2018</span>),
]

<span class="hljs-comment"># Loop through list of vehicles and inspect them</span>
<span class="hljs-keyword">for</span> vehicle <span class="hljs-keyword">in</span> vehicles:
    <span class="hljs-keyword">if</span> isinstance(vehicle, Car):
        print(<span class="hljs-string">f"Inspecting <span class="hljs-subst">{vehicle.brand}</span> <span class="hljs-subst">{vehicle.model}</span> (<span class="hljs-subst">{type(vehicle).__name__}</span>)"</span>)
        vehicle.start()
        vehicle.stop()
    <span class="hljs-keyword">elif</span> isinstance(vehicle, Motorcycle):
        print(<span class="hljs-string">f"Inspecting <span class="hljs-subst">{vehicle.brand}</span> <span class="hljs-subst">{vehicle.model}</span> (<span class="hljs-subst">{type(vehicle).__name__}</span>)"</span>)
        vehicle.start_bike()
        vehicle.stop_bike()
    <span class="hljs-keyword">else</span>:
        <span class="hljs-keyword">raise</span> Exception(<span class="hljs-string">"Object is not a valid vehicle"</span>)
</code></pre>
<p>Notice the ugly code inside the <code>for</code> loop! Because <code>vehicles</code> is a list of any type of object, we have to figure out what type of object we are dealing with inside each loop before we can access any information on the object.</p>
<p>This code will continue to get uglier as we add more vehicle types. For example, if we <em>extended</em> our codebase to include a new <code>Plane</code> class, then we’d need to <em>modify</em> (and potentially break) existing code – we’d have to add another conditional check in the <code>for</code> loop for planes.</p>
<h3 id="heading-introducing-polymorphism"><strong>Introducing: Polymorphism…</strong></h3>
<p>Cars and motorcycles are both vehicles. They both share some common properties and methods. So, let’s create a parent class that contains these shared properties and methods:</p>
<p>Parent class (or "superclass"):</p>
<pre><code class="lang-python"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Vehicle</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, brand, model, year</span>):</span>
        self.brand = brand
        self.model = model
        self.year = year

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">start</span>(<span class="hljs-params">self</span>):</span>
        print(<span class="hljs-string">"Vehicle is starting."</span>)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">stop</span>(<span class="hljs-params">self</span>):</span>
        print(<span class="hljs-string">"Vehicle is stopping."</span>)
</code></pre>
<p><code>Car</code> and <code>Motorcycle</code> can now <em>inherit</em> from <code>Vehicle</code>. Let’s create the child classes (or "subclasses") of the <code>Vehicle</code> superclass:</p>
<pre><code class="lang-python"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Car</span>(<span class="hljs-params">Vehicle</span>):</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, brand, model, year, number_of_doors</span>):</span>
        super().__init__(brand, model, year)
        self.number_of_doors = number_of_doors

    <span class="hljs-comment"># Below, we "override" the start and stop methods, inherited from Vehicle, to provide car-specific behaviour</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">start</span>(<span class="hljs-params">self</span>):</span>
        print(<span class="hljs-string">"Car is starting."</span>)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">stop</span>(<span class="hljs-params">self</span>):</span>
        print(<span class="hljs-string">"Car is stopping."</span>)
</code></pre>
<pre><code class="lang-python"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Motorcycle</span>(<span class="hljs-params">Vehicle</span>):</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, brand, model, year</span>):</span>
        super().__init__(brand, model, year)

    <span class="hljs-comment"># Below, we "override" the start and stop methods, inherited from Vehicle, to provide bike-specific behaviour</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">start</span>(<span class="hljs-params">self</span>):</span>
        print(<span class="hljs-string">"Motorcycle is starting."</span>)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">stop</span>(<span class="hljs-params">self</span>):</span>
        print(<span class="hljs-string">"Motorcycle is stopping."</span>)
</code></pre>
<p><code>Car</code> and <code>Motorcycle</code> both extend <code>Vehicle</code>, as they are vehicles. But what’s the point in <code>Car</code> and <code>Motorcycle</code> both extending <code>Vehicle</code> if they are going to implement their own versions of the <code>start()</code> and <code>stop()</code> methods? Look at the code below:</p>
<pre><code class="lang-python"><span class="hljs-comment"># Create list of vehicles to inspect</span>
vehicles = [Car(<span class="hljs-string">"Ford"</span>, <span class="hljs-string">"Focus"</span>, <span class="hljs-number">2008</span>, <span class="hljs-number">5</span>), Motorcycle(<span class="hljs-string">"Honda"</span>, <span class="hljs-string">"Scoopy"</span>, <span class="hljs-number">2018</span>)]

<span class="hljs-comment"># Loop through list of vehicles and inspect them</span>
<span class="hljs-keyword">for</span> vehicle <span class="hljs-keyword">in</span> vehicles:
    <span class="hljs-keyword">if</span> isinstance(vehicle, Vehicle):
        print(<span class="hljs-string">f"Inspecting <span class="hljs-subst">{vehicle.brand}</span> <span class="hljs-subst">{vehicle.model}</span> (<span class="hljs-subst">{type(vehicle).__name__}</span>)"</span>)
        vehicle.start()
        vehicle.stop()
    <span class="hljs-keyword">else</span>:
        <span class="hljs-keyword">raise</span> Exception(<span class="hljs-string">"Object is not a valid vehicle"</span>)
</code></pre>
<p><strong>In this example</strong>:</p>
<ul>
<li><p>We have a list, <code>vehicles</code>, containing instances of both <code>Car</code> and <code>Motorcycle</code>.</p>
</li>
<li><p>We iterate through each vehicle in the list and perform a general inspection on each one.</p>
</li>
<li><p>The inspection process involves starting the vehicle, checking its brand and model, and stopping it afterwards.</p>
</li>
<li><p>Despite the vehicles being of different types, polymorphism allows us to treat them all as instances of the base <code>Vehicle</code> class. The specific implementations of the <code>start()</code> and <code>stop()</code> methods for each vehicle type are invoked dynamically at runtime, based on the actual type of each vehicle.</p>
</li>
</ul>
<p>Because the list can <em>only</em> contain objects that extend the <code>Vehicle</code> class, we know that every object will share some common fields and methods. This means that we can safely call them, without having to worry about whether each specific vehicle has these fields or methods.</p>
<p>This demonstrates how polymorphism enables code to be written in a more generic and flexible manner, allowing for easy extension and maintenance as new types of vehicles are added to the system.</p>
<p>For example, if we wanted to add another vehicle to the list, we don’t have to modify the code used to inspect vehicles (“the client code”). Instead, we can just <em>extend</em> our code base (that is, create a new class), without <em>modifying</em> existing code:</p>
<pre><code class="lang-python"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Plane</span>(<span class="hljs-params">Vehicle</span>):</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, brand, model, year, number_of_doors</span>):</span>
        super().__init__(brand, model, year)
        self.number_of_doors = number_of_doors

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">start</span>(<span class="hljs-params">self</span>):</span>
        print(<span class="hljs-string">"Plane is starting."</span>)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">stop</span>(<span class="hljs-params">self</span>):</span>
        print(<span class="hljs-string">"Plane is stopping."</span>)
</code></pre>
<pre><code class="lang-python"><span class="hljs-comment"># Create list of vehicles to inspect</span>
vehicles = [
    Car(<span class="hljs-string">"Ford"</span>, <span class="hljs-string">"Focus"</span>, <span class="hljs-number">2008</span>, <span class="hljs-number">5</span>),
    Motorcycle(<span class="hljs-string">"Honda"</span>, <span class="hljs-string">"Scoopy"</span>, <span class="hljs-number">2018</span>),

    <span class="hljs-comment">########## ADD A PLANE TO THE LIST: #########</span>

    Plane(<span class="hljs-string">"Boeing"</span>, <span class="hljs-string">"747"</span>, <span class="hljs-number">2015</span>, <span class="hljs-number">16</span>),

    <span class="hljs-comment">############################################</span>
]
</code></pre>
<p>The code to perform the vehicle inspections doesn’t have to change to account for a plane. Everything still works, without having to modify our inspection logic.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Polymorphism allows clients to treat different types of objects in the same way. This greatly improves the flexibility of software and maintainability of software, as new classes can be created without you having to modify (often by adding extra <code>if</code>/<code>else if</code> blocks) existing working and tested code.</p>
<h2 id="heading-further-learning">Further Learning</h2>
<p>Polymorphism is related to many other object-oriented programming principles, such as <em>dependency injection</em> and the <em>open-closed</em> SOLID principle. If you’d like to master OOP, then check out my Udemy course:</p>
<ul>
<li><a target="_blank" href="https://www.udemy.com/course/python-oop-object-oriented-programming-from-beginner-to-pro">Python OOP: Object Oriented Programming From Beginner to Pro 🎥</a></li>
</ul>
<p>If you prefer book to video, check out my books:</p>
<ul>
<li><p><a target="_blank" href="https://www.amazon.com/dp/B0DR6ZPZQ8">Amazon Kindle and paperback 📖</a></p>
</li>
<li><p><a target="_blank" href="https://doabledanny.gumroad.com/l/python-oop-beginner-to-pro">Gumroad PDF 📖</a></p>
</li>
</ul>
<p>Thanks for reading :)</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ What are the SOLID Principles in C#? Explained With Code Examples ]]>
                </title>
                <description>
                    <![CDATA[ The SOLID Principles are five software design principles that help you to write high quality, flexible, maintainable, reusable, testable, and readable software. If you plan to work with object-oriented software, it is crucial to understand these five... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/what-are-the-solid-principles-in-csharp/</link>
                <guid isPermaLink="false">671a62b68210490d9d68e83f</guid>
                
                    <category>
                        <![CDATA[ Object Oriented Programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ C# ]]>
                    </category>
                
                    <category>
                        <![CDATA[ software development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ design patterns ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Software Engineering ]]>
                    </category>
                
                    <category>
                        <![CDATA[ software architecture ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Danny ]]>
                </dc:creator>
                <pubDate>Thu, 24 Oct 2024 15:07:34 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1729777076695/7d956373-1835-4823-9a6a-d2d232cd64d5.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>The SOLID Principles are five software design principles that help you to write high quality, flexible, maintainable, reusable, testable, and readable software. If you plan to work with object-oriented software, it is crucial to understand these five principles.</p>
<p>The SOLID Principles were introduced by a software engineer named Robert C. Martin (also known as "Uncle Bob") in the early 2000s. Uncle Bob’s goal was to promote good software design practices, particularly in object-oriented programming (OOP), by addressing common problems developers face as software systems grow in size and complexity.</p>
<p>Here are the five SOLID principles:</p>
<ul>
<li><p><strong>S</strong>: <a class="post-section-overview" href="#heading-single-responsibility-principle-srp">Single Responsibility Principle (SRP)</a></p>
</li>
<li><p><strong>O</strong>: <a class="post-section-overview" href="#heading-open-closed-principle-ocp">Open-closed Principle (OCP)</a></p>
</li>
<li><p><strong>L</strong>: <a class="post-section-overview" href="#heading-liskov-substitution-principle-lsp">Liskov Substitution Principle (LSP)</a></p>
</li>
<li><p><strong>I</strong>: <a class="post-section-overview" href="#heading-interface-segregation-principle-isp">Interface Segregation Principle (ISP)</a></p>
</li>
<li><p><strong>D</strong>: <a class="post-section-overview" href="#heading-dependency-inversion-principle-dip">Dependency Inversion Principle (DIP)</a></p>
</li>
</ul>
<p>By following these principles, you can create software designs that are easier to understand, maintain, and extend, leading to higher-quality software that is more robust and adaptable to change.</p>
<p>In this article, to demonstrate each principle, I’ll first show you a bad code example in C# that violates the principle. We will then discuss the issues this bad code causes, and then solve those issues by refactoring the code to satisfy the principle.</p>
<p>First up we have the…</p>
<h2 id="heading-single-responsibility-principle-srp-in-c">Single Responsibility Principle (SRP) in C</h2>
<blockquote>
<p>A class should have only one reason to change, meaning that it should have only one responsibility or purpose.</p>
</blockquote>
<p>This principle encourages you to create classes that are more focussed and perform one single well-defined task, rather than multiple tasks. Breaking up classes into smaller, more focused units makes code easier to understand, maintain, and test.</p>
<p><strong>An example that violates the SRP:</strong></p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">User</span>
{
 <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Username { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
 <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Email { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }

 <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Register</span>(<span class="hljs-params"></span>)</span>
 {
   <span class="hljs-comment">// Register user logic, e.g. save to database...</span>

   <span class="hljs-comment">// Send email notification</span>
   EmailSender emailSender = <span class="hljs-keyword">new</span> EmailSender();
   emailSender.SendEmail(<span class="hljs-string">"Welcome to our platform!"</span>, Email);
 }
}
</code></pre>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">EmailSender</span>
{
 <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">SendEmail</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> message, <span class="hljs-keyword">string</span> recipient</span>)</span>
 {
   <span class="hljs-comment">// Email sending logic</span>
   Console.WriteLine(<span class="hljs-string">$"Sending email to <span class="hljs-subst">{recipient}</span>: <span class="hljs-subst">{message}</span>"</span>);
 }
}
</code></pre>
<p>In this example, the <code>User</code> class manages user data (username and email), and contains logic for registering a user. This violates the SRP because the class has more than one reason to change. It could change due to:</p>
<ul>
<li><p>Modifications in user data management – for example adding more fields, such as <code>firstName</code>, <code>gender</code>, <code>hobbies</code>.</p>
</li>
<li><p>Modifications to the logic of registering a user, for example we may choose to fetch a user from the database by their username rather than their email.</p>
</li>
</ul>
<p>To adhere to the Single Responsibility Principle, we should separate these responsibilities into separate classes. </p>
<p><strong>Refactoring the code to satisfy the SRP</strong>:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">User</span>
{
 <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Username { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
 <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Email { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
}
</code></pre>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">EmailSender</span>
{
 <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">SendEmail</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> message, <span class="hljs-keyword">string</span> recipient</span>)</span>
 {
   <span class="hljs-comment">// Email sending logic</span>
   Console.WriteLine(<span class="hljs-string">$"Sending email to <span class="hljs-subst">{recipient}</span>: <span class="hljs-subst">{message}</span>"</span>);
 }
}
</code></pre>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">UserService</span>
{
 <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">RegisterUser</span>(<span class="hljs-params">User user</span>)</span>
 {
   <span class="hljs-comment">// Register user logic...</span>

   EmailSender emailSender = <span class="hljs-keyword">new</span> EmailSender();
   emailSender.SendEmail(<span class="hljs-string">"Welcome to our platform!"</span>, user.Email);
 }
}
</code></pre>
<p>In the refactored code, the <code>User</code> class is responsible solely for representing user data. The <code>UserService</code> class now handles user registration, separating concerns related to user data management from user registration logic. The <code>UserService</code> class is responsible only for the business logic of registering a user.</p>
<p>This separation of responsibilities adheres to the Single Responsibility Principle, making the code easier to understand, maintain, and extend.</p>
<h2 id="heading-openclosed-principle-ocp-in-c">Open/Closed Principle (OCP) in C</h2>
<blockquote>
<p>Software entities (classes, modules, functions, etc.) should be open for extension but closed for modification.</p>
</blockquote>
<p>This principle promotes the idea that existing code should be able to be extended with new functionality without modifying its source code. It encourages the use of abstraction and polymorphism to achieve this goal, allowing for code to be easily extended through inheritance or composition.</p>
<p>(By the way, if you don’t understand these fundamental OOP concepts, such as abstraction, polymorphism, inheritance and composition — then check out my book, <a target="_blank" href="https://www.amazon.com/Mastering-Design-Patterns-Beginner-Friendly-Principles/dp/B0DB6MLYYZ">Mastering Design Patterns in C#: A Beginner-Friendly Guide, Including OOP and SOLID Principles on Amazon</a> or <a target="_blank" href="https://doabledanny.gumroad.com/l/ennyj?layout=profile">Gumroad</a>.)</p>
<p>Let's consider an example of a <code>Shape</code> class hierarchy that calculates the area of different geometric shapes. Initially, this violates the Open/Closed Principle because adding a new shape requires modifying the existing code:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">enum</span> ShapeType
{
 Circle,
 Rectangle
}
</code></pre>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Shape</span>
{
 <span class="hljs-keyword">public</span> ShapeType Type { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
 <span class="hljs-keyword">public</span> <span class="hljs-keyword">double</span> Radius { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
 <span class="hljs-keyword">public</span> <span class="hljs-keyword">double</span> Length { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
 <span class="hljs-keyword">public</span> <span class="hljs-keyword">double</span> Width { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }

 <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">double</span> <span class="hljs-title">CalculateArea</span>(<span class="hljs-params"></span>)</span>
 {
   <span class="hljs-keyword">switch</span> (Type)
   {
     <span class="hljs-keyword">case</span> ShapeType.Circle:
       <span class="hljs-keyword">return</span> Math.PI * Math.Pow(Radius, <span class="hljs-number">2</span>);
     <span class="hljs-keyword">case</span> ShapeType.Rectangle:
       <span class="hljs-keyword">return</span> Length * Width;
     <span class="hljs-keyword">default</span>:
       <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> InvalidOperationException(<span class="hljs-string">"Unsupported shape type."</span>);
   }
 }
}
</code></pre>
<p>In this example, the <code>Shape</code> class has a method, <code>CalculateArea()</code>, that calculates the area based on the type of shape. Adding a new shape, such as a triangle, would require modifying the existing <code>Shape</code> class, violating the OCP.</p>
<p>To adhere to the Open/Closed Principle, we should design the system in a way that allows for extension without modification. Let's refactor the code using inheritance and polymorphism:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Shape</span>
{
 <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> <span class="hljs-keyword">double</span> <span class="hljs-title">CalculateArea</span>(<span class="hljs-params"></span>)</span>;
}
</code></pre>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Circle</span> : <span class="hljs-title">Shape</span>
{
 <span class="hljs-keyword">public</span> <span class="hljs-keyword">double</span> Radius { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }

 <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">override</span> <span class="hljs-keyword">double</span> <span class="hljs-title">CalculateArea</span>(<span class="hljs-params"></span>)</span>
 {
   <span class="hljs-keyword">return</span> Math.PI * Math.Pow(Radius, <span class="hljs-number">2</span>);
 }
}
</code></pre>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Rectangle</span> : <span class="hljs-title">Shape</span>
{
 <span class="hljs-keyword">public</span> <span class="hljs-keyword">double</span> Length { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
 <span class="hljs-keyword">public</span> <span class="hljs-keyword">double</span> Width { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }

 <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">override</span> <span class="hljs-keyword">double</span> <span class="hljs-title">CalculateArea</span>(<span class="hljs-params"></span>)</span>
 {
   <span class="hljs-keyword">return</span> Length * Width;
 }
}
</code></pre>
<p>In this refactored code, we define an abstract <code>Shape</code> class with an abstract <code>CalculateArea()</code> method. Concrete shape classes (<code>Circle</code> and <code>Rectangle</code>) inherit from the <code>Shape</code> class and provide their own implementations of <code>CalculateArea()</code>.</p>
<p>Adding a new shape, such as a triangle, would involve creating a new class – <em>extending</em> the codebase – that inherits from <code>Shape</code> and implements <code>CalculateArea()</code>, without <em>modifying</em> existing code. This adheres to the OCP by allowing for extension without modification.</p>
<p>Being able to add functionality without modifying existing code means that we don’t have to worry as much about breaking existing working code and introducing bugs.</p>
<p>Following the OCP encourages us to design our software so that we add new features only by adding new code. This helps us to build loosely-coupled, maintainable software.</p>
<h2 id="heading-liskov-substitution-principle-lsp-in-c">Liskov Substitution Principle (LSP) in C</h2>
<blockquote>
<p>Objects of a superclass should be replaceable with objects of its subclass without affecting the correctness of the program.</p>
</blockquote>
<p>This principle ensures that inheritance hierarchies are well-designed and that subclasses adhere to the contracts defined by their superclasses.</p>
<p>Violations of the LSP can lead to unexpected behavior or errors when substituting objects, making code harder to reason about and maintain.</p>
<p>Let's consider an example involving a <code>Rectangle</code> class and a <code>Square</code> class, which inherit from a common <code>Shape</code> class. Initially, we'll violate the LSP by not adhering to the behavior expected from these classes. Then, we'll fix it to ensure that the principle is respected.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Shape</span>
{
 <span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> <span class="hljs-keyword">double</span> Area { <span class="hljs-keyword">get</span>; }
}
</code></pre>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Rectangle</span> : <span class="hljs-title">Shape</span>
{
 <span class="hljs-keyword">public</span> <span class="hljs-keyword">virtual</span> <span class="hljs-keyword">double</span> Width { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }

 <span class="hljs-keyword">public</span> <span class="hljs-keyword">virtual</span> <span class="hljs-keyword">double</span> Height { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }

 <span class="hljs-keyword">public</span> <span class="hljs-keyword">override</span> <span class="hljs-keyword">double</span> Area =&gt; Width * Height;
}
</code></pre>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Square</span> : <span class="hljs-title">Rectangle</span>
{
 <span class="hljs-keyword">public</span> <span class="hljs-keyword">override</span> <span class="hljs-keyword">double</span> Width
 {
   <span class="hljs-keyword">get</span> =&gt; <span class="hljs-keyword">base</span>.Width;
   <span class="hljs-keyword">set</span> =&gt; <span class="hljs-keyword">base</span>.Width = <span class="hljs-keyword">base</span>.Height = <span class="hljs-keyword">value</span>;
 }

 <span class="hljs-keyword">public</span> <span class="hljs-keyword">override</span> <span class="hljs-keyword">double</span> Height
 {
   <span class="hljs-keyword">get</span> =&gt; <span class="hljs-keyword">base</span>.Height;
   <span class="hljs-keyword">set</span> =&gt; <span class="hljs-keyword">base</span>.Height = <span class="hljs-keyword">base</span>.Width = <span class="hljs-keyword">value</span>;
 }
}
</code></pre>
<p>Now, let’s test out if <code>Rectangle</code> calculates its area correctly:</p>
<pre><code class="lang-csharp"><span class="hljs-comment">// Program.cs</span>

<span class="hljs-keyword">var</span> rect = <span class="hljs-keyword">new</span> Rectangle();
rect.Height = <span class="hljs-number">10</span>;
rect.Width = <span class="hljs-number">5</span>;

System.Console.WriteLine(<span class="hljs-string">"Expected area = 10 * 5 = 50."</span>);

System.Console.WriteLine(<span class="hljs-string">"Calculated area = "</span> + rect.Area);
</code></pre>
<p>Running the program:</p>
<pre><code class="lang-plaintext">Expected area = 10 * 5 = 50.

Calculated area = 50
</code></pre>
<p>Perfect!</p>
<p>Now, in our program, the <code>Square</code> class inherits from, or extends, the <code>Rectangle</code> class, because, mathematically, a square is just a special type of rectangle, where its height equals its width. Because of this, we decided that <code>Square</code> should extend <code>Rectangle</code> – it’s like saying “a square <em>is a</em> (special type of) rectangle”.</p>
<p>But look what happens if we substitute the <code>Rectangle</code> class for the <code>Square</code> class:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">var</span> rect = <span class="hljs-keyword">new</span> Square();
rect.Height = <span class="hljs-number">10</span>;
rect.Width = <span class="hljs-number">5</span>;

System.Console.WriteLine(<span class="hljs-string">"Expected area = 10 * 5 = 50."</span>);

System.Console.WriteLine(<span class="hljs-string">"Calculated area = "</span> + rect.Area);
</code></pre>
<pre><code class="lang-plaintext">Expected area = 10 * 5 = 50.

Calculated area = 25
</code></pre>
<p>Oh dear, LSP has been violated: we replaced the object of a superclass (<code>Rectangle</code>) with an object of its subclass (<code>Square</code>), and it affected the correctness of our program. By modeling <code>Square</code> as a subclass of <code>Rectangle</code>, and allowing width and height to be independently set, we violate the LSP. When setting the width and height of a <code>Square</code>, it should retain its squareness, but our implementation allows for inconsistency.</p>
<p>Let’s fix this to satisfy LSP:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Shape</span>
{
 <span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> <span class="hljs-keyword">double</span> Area { <span class="hljs-keyword">get</span>; }
}
</code></pre>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Rectangle</span> : <span class="hljs-title">Shape</span>
{
 <span class="hljs-keyword">public</span> <span class="hljs-keyword">double</span> Width { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }

 <span class="hljs-keyword">public</span> <span class="hljs-keyword">double</span> Height { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }

 <span class="hljs-keyword">public</span> <span class="hljs-keyword">override</span> <span class="hljs-keyword">double</span> Area =&gt; Width * Height;
}
</code></pre>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Square</span> : <span class="hljs-title">Shape</span>
{
 <span class="hljs-keyword">private</span> <span class="hljs-keyword">double</span> sideLength;

 <span class="hljs-keyword">public</span> <span class="hljs-keyword">double</span> SideLength
 {
   <span class="hljs-keyword">get</span> =&gt; sideLength;
   <span class="hljs-keyword">set</span>
   {
     sideLength = <span class="hljs-keyword">value</span>;
   }
 }

 <span class="hljs-keyword">public</span> <span class="hljs-keyword">override</span> <span class="hljs-keyword">double</span> Area =&gt; sideLength * sideLength;
}
</code></pre>
<pre><code class="lang-csharp"><span class="hljs-comment">// Program.cs</span>

Shape rectangle = <span class="hljs-keyword">new</span> Rectangle { Width = <span class="hljs-number">5</span>, Height = <span class="hljs-number">4</span> };

Console.WriteLine(<span class="hljs-string">$"Area of the rectangle: <span class="hljs-subst">{rectangle.Area}</span>"</span>);

Shape square = <span class="hljs-keyword">new</span> Square { SideLength = <span class="hljs-number">5</span> };

Console.WriteLine(<span class="hljs-string">$"Area of the square: <span class="hljs-subst">{square.Area}</span>"</span>);
</code></pre>
<p>In this corrected example, we redesign the <code>Square</code> class to directly set the side length. Now, a <code>Square</code> is correctly modeled as a subclass of <code>Shape</code>, and it adheres to the Liskov Substitution Principle.</p>
<p>How does this satisfy LSP? Well, we have a superclass, <code>Shape</code>, and subclasses <code>Rectangle</code> and <code>Square</code>. Both <code>Rectangle</code> and <code>Square</code> maintain the correct expected behavior of a <code>Shape</code> — we can substitute a square for a rectangle and the area will still be calculated correctly.</p>
<h2 id="heading-interface-segregation-principle-isp-in-c">Interface Segregation Principle (ISP) in C</h2>
<blockquote>
<p>Clients should not be forced to depend on interfaces they do not use.</p>
</blockquote>
<p>This principle encourages the creation of fine-grained interfaces that contain only the methods required by the clients that use them. It helps to prevent the creation of "fat" interfaces that force clients to implement unnecessary methods, leading to cleaner and more maintainable code.</p>
<p>Let's consider an example involving 2D and 3D shapes, initially violating the ISP.</p>
<p><strong>Violating ISP:</strong></p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">interface</span> <span class="hljs-title">IShape</span>
{
 <span class="hljs-function"><span class="hljs-keyword">double</span> <span class="hljs-title">Area</span>(<span class="hljs-params"></span>)</span>;
 <span class="hljs-function"><span class="hljs-keyword">double</span> <span class="hljs-title">Volume</span>(<span class="hljs-params"></span>)</span>; <span class="hljs-comment">// problem: 2D shapes don't have volume!</span>
}
</code></pre>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Circle</span> : <span class="hljs-title">IShape</span>
{
 <span class="hljs-keyword">public</span> <span class="hljs-keyword">double</span> Radius { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }

 <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">double</span> <span class="hljs-title">Area</span>(<span class="hljs-params"></span>)</span>
 {
   <span class="hljs-keyword">return</span> Math.PI * Math.Pow(Radius, <span class="hljs-number">2</span>);
 }

 <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">double</span> <span class="hljs-title">Volume</span>(<span class="hljs-params"></span>)</span>
 {
   <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> InvalidOperationException(<span class="hljs-string">"Volume not applicable for 2D shapes."</span>);
 }
}
</code></pre>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Sphere</span> : <span class="hljs-title">IShape</span>
{
 <span class="hljs-keyword">public</span> <span class="hljs-keyword">double</span> Radius { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }

 <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">double</span> <span class="hljs-title">Area</span>(<span class="hljs-params"></span>)</span>
 {
   <span class="hljs-keyword">return</span> <span class="hljs-number">4</span> * Math.PI * Math.Pow(Radius, <span class="hljs-number">2</span>);
 }

 <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">double</span> <span class="hljs-title">Volume</span>(<span class="hljs-params"></span>)</span>
 {
   <span class="hljs-keyword">return</span> (<span class="hljs-number">4.0</span> / <span class="hljs-number">3.0</span>) * Math.PI * Math.Pow(Radius, <span class="hljs-number">3</span>);
 }
}
</code></pre>
<p>In this example, we have an <code>IShape</code> interface representing both 2D and 3D shapes. However, the <code>Volume()</code> method is problematic for 2D shapes, like <code>Circle</code> and <code>Rectangle</code>, because they don't have volume. This violates the ISP because clients (classes using the <code>IShape</code> interface) may be forced to depend on methods they do not need.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">var</span> circle = <span class="hljs-keyword">new</span> Circle();
circle.Radius = <span class="hljs-number">10</span>;

System.Console.WriteLine(circle.Area());
System.Console.WriteLine(circle.Volume()); <span class="hljs-comment">// My text editor doesn't flag a problem...</span>

<span class="hljs-keyword">var</span> sphere = <span class="hljs-keyword">new</span> Sphere();
sphere.Radius = <span class="hljs-number">10</span>;

System.Console.WriteLine(sphere.Area());
System.Console.WriteLine(sphere.Volume());
</code></pre>
<p>Usually, if I try to call a method on an object that doesn’t exist, VS Code will tell me that I’m making a mistake. But above, when I call <code>circle.Volume()</code>, VS code is like “no problem”. And VS code is correct, because the <code>IShape</code> interface forces <code>Circle</code> to implement a <code>Volume()</code> method, even though circles don’t have volume.</p>
<p>It’s easy to see how violating ISP can introduce bugs into a program – above, everything looks fine, until we run the program and an exception gets thrown.</p>
<p><strong>Fixing ISP</strong></p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">interface</span> <span class="hljs-title">IShape2D</span>
{
 <span class="hljs-function"><span class="hljs-keyword">double</span> <span class="hljs-title">Area</span>(<span class="hljs-params"></span>)</span>;
}
</code></pre>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">interface</span> <span class="hljs-title">IShape3D</span>
{
 <span class="hljs-function"><span class="hljs-keyword">double</span> <span class="hljs-title">Area</span>(<span class="hljs-params"></span>)</span>;
 <span class="hljs-function"><span class="hljs-keyword">double</span> <span class="hljs-title">Volume</span>(<span class="hljs-params"></span>)</span>;
}
</code></pre>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Circle</span> : <span class="hljs-title">IShape2D</span>
{
 <span class="hljs-keyword">public</span> <span class="hljs-keyword">double</span> Radius { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }

 <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">double</span> <span class="hljs-title">Area</span>(<span class="hljs-params"></span>)</span>
 {
   <span class="hljs-keyword">return</span> Math.PI * Math.Pow(Radius, <span class="hljs-number">2</span>);
 }
}
</code></pre>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Sphere</span> : <span class="hljs-title">IShape3D</span>
{
 <span class="hljs-keyword">public</span> <span class="hljs-keyword">double</span> Radius { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }

 <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">double</span> <span class="hljs-title">Area</span>(<span class="hljs-params"></span>)</span>
 {
   <span class="hljs-keyword">return</span> <span class="hljs-number">4</span> * Math.PI * Math.Pow(Radius, <span class="hljs-number">2</span>);
 }

 <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">double</span> <span class="hljs-title">Volume</span>(<span class="hljs-params"></span>)</span>
 {
   <span class="hljs-keyword">return</span> (<span class="hljs-number">4.0</span> / <span class="hljs-number">3.0</span>) * Math.PI * Math.Pow(Radius, <span class="hljs-number">3</span>);
 }
}
</code></pre>
<p>In the fixed example, we've <em>segregated</em> the <code>IShape</code> interface into two smaller, more focused interfaces: <code>IShape2D</code> and <code>IShape3D</code>. Each shape class now implements only the interface that is relevant to its functionality.</p>
<p>This adheres to the Interface Segregation Principle by ensuring that clients are not forced to depend on methods that they do not use. Clients can now depend only on the interfaces that they need, promoting better code reuse and flexibility.</p>
<p>Next up, the fifth and final SOLID principle…</p>
<h2 id="heading-dependency-inversion-principle-dip-in-c">Dependency Inversion Principle (DIP) in C</h2>
<blockquote>
<p>High-level modules should not depend on low-level modules. Both should depend on abstractions.</p>
</blockquote>
<p>Dependency Inversion is the strategy of depending upon interfaces or abstract classes rather than upon concrete classes. This principle promotes decoupling between modules and promotes the use of interfaces or abstract classes to define dependencies, allowing for more flexible and testable code.</p>
<p>Let's start with an example violating the DIP and then we’ll correct it.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Engine</span> <span class="hljs-comment">// Engine is our "low-level" module</span>
{
 <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Start</span>(<span class="hljs-params"></span>)</span>
 {
   System.Console.WriteLine(<span class="hljs-string">"Engine started."</span>);
 }
}
</code></pre>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Car</span> <span class="hljs-comment">// Car is our "high-level" module</span>
{
 <span class="hljs-keyword">private</span> Engine engine;

 <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">Car</span>(<span class="hljs-params"></span>)</span>
 {
   <span class="hljs-keyword">this</span>.engine = <span class="hljs-keyword">new</span> Engine(); <span class="hljs-comment">// Direct dependency on concrete Engine class</span>
 }

 <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">StartCar</span>(<span class="hljs-params"></span>)</span>
 {
   engine.Start();
   System.Console.WriteLine(<span class="hljs-string">"Car started."</span>);
 }
}
</code></pre>
<p>In this example:</p>
<ul>
<li><p>The <code>Car</code> class directly creates an instance of the <code>Engine</code> class, leading to a tight coupling between Car and Engine.</p>
</li>
<li><p>If the <code>Engine</code> class changes, it may affect the <code>Car</code> class, violating the Dependency Inversion Principle.</p>
</li>
</ul>
<p>The UML diagram below shows that <code>Car</code> depends on <code>Engine</code>:</p>
<p><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXdbd6IZ4TfDmGCPIjsJJHTtEw7_WBxCP-H1cSme78Ze7qJq0fG6tQzNo7A-IbgnnruAZwMBhjuJoozA0rzA9RM35Pu9vWpk4I2Hp6Szk7Ns_kTFbu2oIIfHQa9ceBembsjN8EUlZLkQuB863NyzeeSn7qY?key=p75tPpeumlH4kqsSJuxz6w" alt="AD_4nXdbd6IZ4TfDmGCPIjsJJHTtEw7_WBxCP-H1cSme78Ze7qJq0fG6tQzNo7A-IbgnnruAZwMBhjuJoozA0rzA9RM35Pu9vWpk4I2Hp6Szk7Ns_kTFbu2oIIfHQa9ceBembsjN8EUlZLkQuB863NyzeeSn7qY?key=p75tPpeumlH4kqsSJuxz6w" width="728" height="728" loading="lazy"></p>
<p>But what do we mean by “high level” and “low level” classes?</p>
<p><strong>High-Level Class</strong>: The high-level class is typically the one that represents the main functionality or business logic of the application. It orchestrates the interaction between various components and is often more abstract in nature.</p>
<p>In this example, the <code>Car</code> class can be considered the high-level class. It represents the main functionality related to starting the car and driving it. The <code>Car</code> class is concerned with the overall behavior of the car, such as controlling its movement.</p>
<p><strong>Low-Level Class</strong>: The low-level class is usually one that provides specific functionality or services that are used by the high-level class. It typically deals with implementation details and is more concrete in nature.</p>
<p>In this example, the <code>Engine</code> class can be considered the low-level class. It provides the specific functionality related to starting the engine. The <code>Engine</code> class encapsulates the details of how the engine operates, such as ignition and combustion.</p>
<p>So in summary, the <code>Car</code> class is the high-level class, representing the main functionality of the application related to the car's behavior.</p>
<p>The <code>Engine</code> class is the low-level class, providing specific functionality related to the operation of the engine, which is used by the Car class.</p>
<p><strong>Fixing DIP:</strong></p>
<p>To adhere to the Dependency Inversion Principle, we introduce an abstraction (interface) between <code>Car</code> and <code>Engine</code>, allowing <code>Car</code> to depend on an abstraction instead of a concrete implementation.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">interface</span> <span class="hljs-title">IEngine</span>
{
 <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">Start</span>(<span class="hljs-params"></span>)</span>;
}
</code></pre>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Engine</span> : <span class="hljs-title">IEngine</span>
{
 <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Start</span>(<span class="hljs-params"></span>)</span>
 {
   System.Console.WriteLine(<span class="hljs-string">"Engine started."</span>);
 }
}
</code></pre>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Car</span>
{
 <span class="hljs-keyword">private</span> IEngine engine;

 <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">Car</span>(<span class="hljs-params">IEngine engine</span>)</span>
 {
   <span class="hljs-keyword">this</span>.engine = engine;
 }

 <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">StartCar</span>(<span class="hljs-params"></span>)</span>
 {
   engine.Start();
   System.Console.WriteLine(<span class="hljs-string">"Car started."</span>);
 }
}
</code></pre>
<p>We can now <em>inject</em> any type of engine into <code>Car</code> implementations:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">var</span> engine = <span class="hljs-keyword">new</span> Engine(); <span class="hljs-comment">// concrete implementation to be "injected" into the car</span>

<span class="hljs-keyword">var</span> car = <span class="hljs-keyword">new</span> Car(engine);

car.StartCar();
</code></pre>
<p>From the UML diagram below, we can see that both objects now depend on the abstraction level of the interface. <code>Engine</code> has inverted its dependency on <code>Car</code>.</p>
<p><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXf2Wes5g5HoeLNGoo4weo-gO6AVdVJ1WbRZxUfTEXIFROup8qCeUiQ8l5CsrwXkC5I1_0i3Q5DyzN5wpXSgjol2_RNFysFKpjMyj4SdEI2lFOplOs-uCUxZGEWE9fI4sFzMKfQOvOx33HKViFcXoqTVmi2s2FcLvCobCCZAvA?key=hfr-bV5v9p97pXexBFuY1A" alt="AD_4nXf2Wes5g5HoeLNGoo4weo-gO6AVdVJ1WbRZxUfTEXIFROup8qCeUiQ8l5CsrwXkC5I1_0i3Q5DyzN5wpXSgjol2_RNFysFKpjMyj4SdEI2lFOplOs-uCUxZGEWE9fI4sFzMKfQOvOx33HKViFcXoqTVmi2s2FcLvCobCCZAvA?key=hfr-bV5v9p97pXexBFuY1A" width="564" height="1248" loading="lazy"></p>
<p>In this corrected example:</p>
<ol>
<li><p>We define an interface <code>IEngine</code> representing the behavior of an engine.</p>
</li>
<li><p>The <code>Engine</code> class implements the <code>IEngine</code> interface.</p>
</li>
<li><p>The <code>Car</code> class now depends on the <code>IEngine</code> interface instead of the concrete <code>Engine</code> class.</p>
</li>
<li><p>Dependency injection is used to inject the <code>IEngine</code> implementation into the <code>Car</code> class, promoting loose coupling. Now, if we want to give a car a different type of engine, for example a <code>FastEngine</code>, we can inject that in instead. </p>
</li>
<li><p>Now, if the implementation of the engine changes, it won't affect the <code>Car</code> class as long as it adheres to the <code>IEngine</code> interface.</p>
</li>
</ol>
<p>Dependency Injection (DI) offers several advantages in software development:</p>
<ul>
<li><p><strong>Decoupling</strong>: DI promotes loose coupling between components by removing direct dependencies. Components rely on abstractions rather than concrete implementations, making them more independent and easier to maintain.</p>
</li>
<li><p><strong>Testability</strong>: Dependency injection simplifies unit testing by allowing components to be easily replaced with mock or stub implementations during testing. This enables isolated testing of individual components without relying on their dependencies.</p>
</li>
<li><p><strong>Flexibility</strong>: DI provides flexibility in configuring and swapping dependencies at runtime. It allows different implementations of dependencies to be used interchangeably without modifying the client code, facilitating runtime customization and extensibility.</p>
</li>
<li><p><strong>Readability and Maintainability</strong>: By explicitly specifying dependencies in the constructor or method parameters, DI improves code readability and makes the codebase easier to understand. It also reduces the risk of hidden dependencies, leading to more maintainable and understandable code.</p>
</li>
<li><p><strong>Reusability</strong>: DI promotes component reusability by decoupling them from their specific contexts or environments. Components can be designed to be independent of the application framework or platform, making them more portable and reusable in different projects or scenarios.</p>
</li>
<li><p><strong>Scalability</strong>: DI simplifies the management of dependencies in large-scale applications by providing a standardised approach for dependency resolution. It helps prevent dependency hell and makes it easier to manage and scale complex systems.</p>
</li>
</ul>
<p>Overall, dependency injection enhances modularity, testability, and maintainability of software systems, contributing to improved software quality and developer productivity.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Congratulations – you now understand the extremely important SOLID principles. These principles are going to save you a lot of headaches during your software development career, and guide you towards creating beautiful, maintainable, flexible, testable software.</p>
<p>If you’d like to take your software development skills to the next level and learn:</p>
<ul>
<li><p>OOP principles: encapsulation, abstraction, inheritance, polymorphism, coupling, composition, composition vs inheritance, fragile base class problem.</p>
</li>
<li><p>All 23 design patterns (“The Gang of Four Design Patterns”) with real world examples.</p>
</li>
<li><p>Unified Modeling Language (UML): the standard way to model classes and the relationships between them.</p>
</li>
</ul>
<p>Then check out my book:</p>
<p><a target="_blank" href="https://www.amazon.com/Mastering-Design-Patterns-Beginner-Friendly-Principles/dp/B0DBZGQZMZ">Mastering Design Patterns in C#: A Beginner-Friendly Guide, Including OOP and SOLID Principles on Amazon</a> (also available on <a target="_blank" href="https://doabledanny.gumroad.com/l/ennyj">Gumroad</a>).</p>
<p>Hopefully this article helps you to become a better OOP software developer!</p>
<p>Thanks for reading,</p>
<p><a target="_blank" href="https://www.youtube.com/channel/UC0URylW_U4i26wN231yRqvA">Danny</a> 😎</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Use React's Context API – Tutorial with Examples ]]>
                </title>
                <description>
                    <![CDATA[ In React, data is typically passed down from parent to child via props. But this can lead to "prop drilling" – where we have to pass props down through lots of components to get them where they're needed. Also, some props (for example, the current au... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/react-context-api-tutorial-examples/</link>
                <guid isPermaLink="false">66c8c99f85ffc69fd028a82c</guid>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React context ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Danny ]]>
                </dc:creator>
                <pubDate>Mon, 22 Jul 2024 15:25:40 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/07/React.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In React, data is typically passed down from parent to child via props. But this can lead to "prop drilling" – where we have to pass props down through lots of components to get them where they're needed.</p>
<p>Also, some props (for example, the current authenticated user, UI theme, or preferred language) will be required by many components within an application.</p>
<p>React's Context API provides a way to share values like these between components without having to explicitly pass them down as a prop through every level of the tree. So, Context is designed to share data that can be considered "global" for a tree of React components.</p>
<h2 id="heading-what-youll-learn-in-this-article">What You'll Learn in This Article</h2>
<ul>
<li><a class="post-section-overview" href="#heading-what-is-the-react-context-api-and-when-should-you-use-it">What is the React Context API and when should you use it?</a></li>
<li><a class="post-section-overview" href="#heading-react-context-api-example-light-and-dark-mode-ui-theme">React Context API example: how to switch between light and dark mode UI themes</a></li>
<li><a class="post-section-overview" href="#heading-how-to-create-multiple-react-contexts">How to create multiple React Contexts (and why you should)</a></li>
<li><a class="post-section-overview" href="#heading-how-to-prevent-the-react-context-re-render-issue">How to prevent the React Context re-render issue</a></li>
<li><a class="post-section-overview" href="#heading-react-context-api-vs-redux">React Context API vs Redux for global state management</a></li>
</ul>
<h2 id="heading-source-code">Source Code</h2>
<p>All examples from this article are in this repo: https://github.com/DoableDanny/React-context-API-tutorial</p>
<p>I also made a video version of this article to make it easier for you to follow along with the examples: <a target="_blank" href="https://www.youtube.com/watch?v=hkGiP6Ur-B4">React Context Tutorial with Examples
</a></p>
<h2 id="heading-what-is-the-react-context-api-and-when-should-you-use-it">What is the React Context API and When Should You Use It?</h2>
<p>The Context API is a feature in React that provides a way to share values like themes, user information, or configuration settings between components without having to explicitly pass props through every level of the component tree. This makes it particularly useful for managing global state, or state that is needed by many components at different nesting levels.</p>
<p>The Context API is a part of the React library, meaning that you don't need to install it as a third-party package in a React application.</p>
<p>So, the Context API can be used for sharing global variables between components in a React app, without having to pass these variables as props down the component tree. This is especially useful if there are components that are deeply nested that need access to variables from higher up components.</p>
<p>Now, let's learn how the Context API works by going through a common use case example for the Context API...</p>
<h2 id="heading-react-context-api-example-light-and-dark-mode-ui-theme">React Context API Example — Light and Dark Mode UI Theme</h2>
<p>A very common real-world usecase for the React Context API is for storing the current user's prefered theme – that is, "light mode" or "dark mode".</p>
<p>Think about it: many of the UI components in a React app will need to know about the current theme, in order to display the approprate styles. Buttons, Headings, the Navbar, the Footer, Dropdowns – lots of components are going to need to display themselves differently depending on the current theme.</p>
<h3 id="heading-the-passing-down-a-prop-solution">The passing-down-a-prop solution</h3>
<p>The most simple and obvious "React" way to solve this would be to create a <code>theme</code> variable in the main top-level <code>App</code> component, and then keep on passing it down as a prop to all of the components in the tree. But this leads to a React problem known as "prop drilling".</p>
<p>Prop drilling is a term used in React to describe the process of passing data from a parent component to a deeply nested child component through multiple intermediary components. This can happen when you need to pass state or functions several levels down the component tree.</p>
<p>Prop drilling example:</p>
<pre><code class="lang-jsx">
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> theme = <span class="hljs-string">'dark'</span>;
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Parent</span> <span class="hljs-attr">theme</span>=<span class="hljs-string">{theme}</span> /&gt;</span></span>;
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Parent</span>(<span class="hljs-params">{ theme }</span>) </span>{
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Child</span> <span class="hljs-attr">theme</span>=<span class="hljs-string">{theme}</span> /&gt;</span></span>;
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Child</span>(<span class="hljs-params">{ theme }</span>) </span>{
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Button</span> <span class="hljs-attr">theme</span>=<span class="hljs-string">{theme}</span> /&gt;</span></span>;
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Button</span>(<span class="hljs-params">{ theme }</span>) </span>{
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">background:</span> <span class="hljs-attr">theme</span> === <span class="hljs-string">'dark'</span> ? '<span class="hljs-attr">black</span>' <span class="hljs-attr">:</span> '<span class="hljs-attr">white</span>' }}&gt;</span>Click me<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></span>;
}
</code></pre>
<p>As you can see, each intermediary component needs to include the prop, even if it doesn't use it, just to pass it down further. This clutters the code and makes it more difficult to understand. </p>
<p>Also, intermediary components that do not use the props might still re-render when the props change, leading to performance issues. This can be particularly problematic in large applications with deep component trees.</p>
<h3 id="heading-context-api-to-the-rescue">Context API To The Rescue</h3>
<p>We can solve this prop drilling issue by using the Context API.</p>
<h4 id="heading-creating-a-context">Creating a context</h4>
<p>First, we need to create the context, and pass in the light theme as the default value:</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// src/contexts/ThemeContext.js</span>

<span class="hljs-keyword">import</span> { createContext } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> themes = {
  <span class="hljs-attr">light</span>: {
    <span class="hljs-attr">background</span>: <span class="hljs-string">"white"</span>,
    <span class="hljs-attr">text</span>: <span class="hljs-string">"black"</span>,
  },
  <span class="hljs-attr">dark</span>: {
    <span class="hljs-attr">background</span>: <span class="hljs-string">"black"</span>,
    <span class="hljs-attr">text</span>: <span class="hljs-string">"white"</span>,
  },
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> ThemeContext = createContext(themes.light);
</code></pre>
<p>Above, we have created a <code>contexts</code> folder inside of our <code>src</code> folder for storing all of our contexts. It's considered good practice to create each context in its own file. In our case, we just need to create a context for storing the current theme.</p>
<p>Notice that contexts are created by calling the <code>createContext()</code> function that comes from the <code>React</code> library. We pass the <code>createContext()</code> function a default value of <code>themes.light</code>.</p>
<h4 id="heading-providing-a-context">Providing a context</h4>
<p>Next, we need to wrap all of the components that need access to the theme in a context provider. The context provider takes a <code>value</code> prop, where we can pass the value that we want to make global. </p>
<p>Below, <code>&lt;Navbar /&gt;</code> and <code>&lt;Button /&gt;</code> will have access to the <code>theme</code> state, even though we haven't explicitly passed it down as a prop. This is because we have wrapped these components in the theme context provider, and passed it the value (<code>theme</code>) that needs to be made global.</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// src/App.js</span>

<span class="hljs-keyword">import</span> React, { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>
<span class="hljs-keyword">import</span> { ThemeContext, themes } <span class="hljs-keyword">from</span> <span class="hljs-string">"./contexts/ThemeContext"</span>
<span class="hljs-keyword">import</span> Navbar <span class="hljs-keyword">from</span> <span class="hljs-string">"./components/Navbar"</span>
<span class="hljs-keyword">import</span> Button <span class="hljs-keyword">from</span> <span class="hljs-string">"./components/Button"</span>

<span class="hljs-keyword">const</span> App = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> [theme, setTheme] = useState(themes.light)

  <span class="hljs-keyword">const</span> toggleTheme = <span class="hljs-function">() =&gt;</span> {
    setTheme(<span class="hljs-function"><span class="hljs-params">state</span> =&gt;</span> (state === themes.light ? themes.dark : themes.light))
  }

  <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">ThemeContext.Provider</span> <span class="hljs-attr">value</span>=<span class="hljs-string">{theme}</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Navbar</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Button</span> <span class="hljs-attr">changeTheme</span>=<span class="hljs-string">{toggleTheme}</span> /&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">ThemeContext.Provider</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  )
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App
</code></pre>
<p>If we also wanted to make <code>setTheme()</code> available throughout our app via context, we could pass the following object to the <code>value</code> prop. We'd then be able to toggle the theme from any component within the Theme Context Provider:</p>
<pre><code class="lang-jsx">&lt;ThemeContext.Provider value={{ theme, setTheme }}&gt;
</code></pre>
<p>Now let's create the <code>Button</code> and <code>Navbar</code> components that will consume the theme context using the <code>useContext()</code> hook. Notice how the CSS styles of the components change depending on the current theme values:</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// src/components/Button.js</span>

<span class="hljs-keyword">import</span> React, { useContext } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>
<span class="hljs-keyword">import</span> { ThemeContext } <span class="hljs-keyword">from</span> <span class="hljs-string">"../contexts/themeContext"</span>

<span class="hljs-keyword">const</span> Button = <span class="hljs-function">(<span class="hljs-params">{ changeTheme }</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> theme = useContext(ThemeContext)

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">button</span>
      <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">backgroundColor:</span> <span class="hljs-attr">theme.background</span>, <span class="hljs-attr">color:</span> <span class="hljs-attr">theme.text</span> }}
      <span class="hljs-attr">onClick</span>=<span class="hljs-string">{changeTheme}</span>
    &gt;</span>
      Toggle theme
    <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></span>
  )
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Button
</code></pre>
<pre><code class="lang-jsx"><span class="hljs-comment">// src/components/Navbar.js</span>

<span class="hljs-keyword">import</span> React, { useContext } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>
<span class="hljs-keyword">import</span> { ThemeContext } <span class="hljs-keyword">from</span> <span class="hljs-string">"../contexts/themeContext"</span>

<span class="hljs-keyword">const</span> Navbar = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> theme = useContext(ThemeContext)

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">nav</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">backgroundColor:</span> <span class="hljs-attr">theme.background</span> }}&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">color:</span> <span class="hljs-attr">theme.text</span> }}&gt;</span>Home<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">color:</span> <span class="hljs-attr">theme.text</span> }}&gt;</span>About<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">nav</span>&gt;</span></span>
  )
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Navbar
</code></pre>
<p><strong>Here are the steps involved in using a context</strong>:</p>
<ol>
<li>Import the context that you want to use (<code>ThemeContext</code> in this example) into the component. </li>
<li>Import the <code>useContext</code> hook from <code>React</code>.</li>
<li>Inside of the component that needs access to the context value(s), call the <code>useContext</code> hook and pass the context that you want to use. Assign this to a variable (<code>const theme = useContext(ThemeContext)</code> in our example)</li>
<li>The component now has access to the global variable, and the component will re-render/be updated every time a value inside of the context is updated.</li>
</ol>
<p>OK, that's everything that we need for this example. Let's now start up our application by running the following command in the project route:</p>
<p><code>npm run start</code></p>
<p>Now let's test things out in the browser.</p>
<p>Light mode:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/light_mode.JPG" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em><strong> Press the Toggle Theme button </strong></em></p>
<p>Dark mode:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/dark_mode.JPG" alt="Image" width="600" height="400" loading="lazy"></p>
<p>And there we go, we've used the context API to share the theme state throughout our application – without having to pass it down as a prop. Cool! 👌</p>
<h2 id="heading-how-to-create-multiple-react-contexts">How to Create Multiple React Contexts</h2>
<p>In our example above, we only created one context, <code>ThemeContext</code>. But what if we had other data that needed to be made global, such as the current logged in user's <code>username</code> and <code>age</code>?</p>
<p>We could just create one big context for storing all variables that needed to be consumed globally:</p>
<pre><code class="lang-jsx">&lt;OneBigContext.Provider value={{ theme, username, age }}&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Button</span> <span class="hljs-attr">changeTheme</span>=<span class="hljs-string">{toggleTheme}</span> /&gt;</span></span>
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Navbar</span> /&gt;</span></span>
&lt;/OneBigContext.Provider&gt;
</code></pre>
<p>But this is considered bad practice, as whenever a context value is updated, all components consuming that context will be re-rendered. This means that all components that only need to know about the <code>theme</code>, and not the user variables, will get re-rendered whenever any of the user variables are updated. This can worsen an app's performance, especially in larger apps with lots of complex components.</p>
<p>We can solve this by creating multiple contexts – one context for the theme and another for the user data – and wrapping our app in both providers, like so:</p>
<pre><code class="lang-jsx">&lt;ThemeContext.Provider value={theme}&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">UserContext.Provider</span> <span class="hljs-attr">value</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">username</span>, <span class="hljs-attr">age</span> }}&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">Button</span> <span class="hljs-attr">changeTheme</span>=<span class="hljs-string">{toggleTheme}</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">Navbar</span> /&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">UserContext.Provider</span>&gt;</span></span>
&lt;/ThemeContext.Provider&gt;
</code></pre>
<p>By only storing related data in each context, we help prevent unnecessary re-renders of components, and improve the performance of our app.</p>
<h2 id="heading-how-to-prevent-the-react-context-re-render-issue">How to Prevent the React Context Re-render Issue</h2>
<p>As we've discussed, whenever a context value is updated, all components consuming that context will be rerendered – even if wrapped in <code>React.memo()</code>. (If you don't know what <code>React.memo()</code> is, don't panic – we'll discuss it soon!) This can worsen an app’s performance. </p>
<p>But we can mitigate this problem with the following methods:</p>
<h3 id="heading-1-use-multiple-react-contexts">1. Use Multiple React Contexts</h3>
<p>This is what we discussed above, and is the "preferred" way of solving the rerender problem (<a target="_blank" href="https://github.com/facebook/react/issues/15156#issuecomment-474590693">see this answer</a>).</p>
<h3 id="heading-2-split-the-component-and-pass-the-needed-value">2. Split the Component and Pass the Needed Value</h3>
<p>You can also split the component up and pass down (as a prop) the needed value from context, with the child components wrapped in <code>React.memo()</code>. Example:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> Card = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> appContextValue = useContext(AppContext);
  <span class="hljs-keyword">const</span> theme = appContextValue.theme;

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">CardTitle</span> <span class="hljs-attr">theme</span>=<span class="hljs-string">{theme}</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">CardDescription</span> <span class="hljs-attr">theme</span>=<span class="hljs-string">{theme}</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">const</span> CardTitle = React.memo(<span class="hljs-function">(<span class="hljs-params">{ theme }</span>) =&gt;</span> {
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">color:</span> <span class="hljs-attr">theme.text</span> }}&gt;</span>This is the Title <span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span></span>;
});

<span class="hljs-keyword">const</span> CardDescription = React.memo(<span class="hljs-function">(<span class="hljs-params">{ theme }</span>) =&gt;</span> {
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">color:</span> <span class="hljs-attr">theme.text</span> }}&gt;</span>lorem ipsum dolor sit amet,<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span></span>;
});
</code></pre>
<p><code>React.memo()</code> is a higher-order component (HOC) in React that is used to optimize functional components by preventing unnecessary re-renders. It does this by memoizing the component, meaning it will only re-render if its props change.</p>
<ul>
<li>Without <code>React.memo()</code>: The components, <code>CardTitle</code> and <code>CardDescription</code>, would re-render whenever their parent, <code>Card</code>, re-renders – even if their props haven't changed. This can lead to performance issues in larger applications or with components that are expensive to render.</li>
<li>With <code>React.memo()</code>: <code>CardTitle</code> and <code>CardDescription</code> only re-render if their props change, reducing unnecessary renders and improving performance.</li>
</ul>
<p>So, by splitting the component up, passing down only the values that are needed as props, and wrapping the components in <code>React.memo()</code>, <code>CardTitle</code> and <code>CardDescription</code> will only be re-rendered if <code>theme</code> is updated, but not if <code>username</code> is updated. </p>
<p>This solution is particularly useful if we can’t split out context for whatever reason.</p>
<h3 id="heading-3-one-component-with-reactusememo-inside">3. One Component with <code>React.useMemo()</code> Inside</h3>
<p>Below, <code>theme</code> is a dependency of <code>useMemo()</code>, so we will only get a re-render of the elements returned by the callback function when <code>theme</code> is changed:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> Card = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> appContextValue = useContext(AppContext);
  <span class="hljs-keyword">const</span> theme = appContextValue.theme;

  <span class="hljs-keyword">return</span> useMemo(
    <span class="hljs-function">() =&gt;</span> (
      <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">CardTitle</span> <span class="hljs-attr">theme</span>=<span class="hljs-string">{theme}</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">CardDescription</span> <span class="hljs-attr">theme</span>=<span class="hljs-string">{theme}</span> /&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
    ),
    [theme]
  );
};

<span class="hljs-keyword">const</span> CardTitle = <span class="hljs-function">(<span class="hljs-params">{ theme }</span>) =&gt;</span> {
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">color:</span> <span class="hljs-attr">theme.text</span> }}&gt;</span>This is the Title <span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span></span>;
};

<span class="hljs-keyword">const</span> CardDescription = <span class="hljs-function">(<span class="hljs-params">{ theme }</span>) =&gt;</span> {
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">color:</span> <span class="hljs-attr">theme.text</span> }}&gt;</span>lorem ipsum dolor sit amet,<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span></span>;
};
</code></pre>
<p>Here's how <code>useMemo()</code> works:</p>
<ol>
<li>The first parameter of <code>useMemo()</code> is a callback function that returns a memoized value. In this case, it returns a React element, or tree of React elements.</li>
<li>The second parameter is an array of dependences. If any of the values in this dependency array are updated, then the callback function provided as the first argument is called, and the elements that the callback function returns are re-rendered.</li>
</ol>
<p>So, <code>useMemo()</code> can be used to only re-render React elements if certain values specified in the dependency array are updated.</p>
<p>By wrapping these elements in <code>useMemo()</code>, and specifying <code>theme</code> as the only dependency, the elements only get re-rendered if <code>theme</code> is updated, but won't get re-rendered if any other context value is updated.</p>
<p>This solution is also particularly useful if we can’t split out context.</p>
<h2 id="heading-react-context-api-vs-redux">React Context API vs Redux</h2>
<p>This is a very common and much-depated topic within the React community. React Context API and Redux are both tools for managing state in a React application, but they have different use cases, strengths, and limitations. </p>
<p>The Context API is a built-in feature of React, with the primary purpose of allowing state to be shared across a tree of React components without prop drilling.</p>
<p>The Context API has a simple API: <code>React.createContext()</code>, <code>Provider</code>, and the <code>useContext()</code> hook. And is good for small to medium-sized apps, as it is straightforward to use, and requires little setup and boilerplate code.</p>
<p>On the other hand, Redux is a state management library that has to be installed as a third-party package into an application. Its primary purpose is to manage application-wide state in a predictable way, especially in large and complex applications.</p>
<h4 id="heading-why-context-api-is-good-for-small-to-medium-sized-apps">Why Context API is good for small-to-medium-sized apps:</h4>
<ul>
<li><strong>Simplicity</strong>: It's simpler than Redux.</li>
<li><strong>Built-in</strong>: It's part of React, so no need to install extra packages, making maintenance of the project easier.</li>
<li><strong>Minimal boilerplate</strong>: Requires less boilerplate and setup than Redux.</li>
</ul>
<h4 id="heading-why-redux-is-good-for-larger-more-complex-applications">Why Redux is good for larger, more complex applications:</h4>
<ul>
<li><strong>Single Store</strong>: Maintains a single store for the entire application state, which makes debugging and testing easier.</li>
<li><strong>Predictable State Updates</strong>: Uses pure functions (reducers) to manage state updates, ensuring predictability and immutability.</li>
<li><strong>Middleware Support</strong>: Powerful middleware system (like redux-thunk or redux-saga) for handling asynchronous actions and side effects.</li>
<li><strong>DevTools Integration</strong>: Excellent developer tools for time-travel debugging and state inspection.</li>
<li><strong>Suitable for Large Apps</strong>: Designed to handle complex state logic and large-scale applications.</li>
</ul>
<p><strong>Redux maintainer, <a target="_blank" href="https://x.com/acemarke?lang=en">Mark Erikson</a>, gives the following reasons for using Redux</strong>:</p>
<ul>
<li>Consistent architectural patterns</li>
<li>Debugging capabilities</li>
<li>Middleware</li>
<li>Addons and extensibility</li>
<li>Cross-platform and cross-framework usage</li>
<li>Depending on your app's setup, much better performance than working with just Context (we don't have to worry about the rerender problem we get with Context, mentioned above – components only rerender when the value they are using updates)</li>
</ul>
<h4 id="heading-in-summary">In summary:</h4>
<ul>
<li>Redux is a more complex state management tool that provides more features and tools. It provides a consistent way of managing state throughout an application, which is very helpful on larger projects with multiple developers (as they won't all be implementing their own styles of state management and making the codebase inconsistent).</li>
<li>React Context API is more straightforward, requires less setup, and is a good solution for smaller to medium sized projects where the added complexity and overhead of using a tool like Redux isn't necessary.</li>
</ul>
<h2 id="heading-thank-you-for-reading">Thank you for reading!</h2>
<p>If you found this article useful, you can hear more from me by:</p>
<ul>
<li><a target="_blank" href="https://www.youtube.com/channel/UC0URylW_U4i26wN231yRqvA">Subscribing to my YouTube channel</a>. I plan to turn it into a React/NextJS/Node-focused channel, with in-depth videos 😎.</li>
<li><a target="_blank" href="https://twitter.com/doabledanny">Following me on Twitter</a> where I tweet about my freelancing journey, side projects and current learnings.</li>
<li><a target="_blank" href="https://www.doabledanny.com/blog/">Checking out my tech blog</a></li>
</ul>
<h3 id="heading-free-react-hooks-course">Free React Hooks Course</h3>
<p>Want to learn all the hooks in React? I created a free 2 hour video explaining all 9 core React Hooks with examples: <a target="_blank" href="https://www.youtube.com/watch?v=TXN6HYGLba4&amp;ab_channel=DoableDanny">React Hooks Tutorial — All React Hooks Explained with Examples</a>. If you enjoy, consider subscribing to <a target="_blank" href="https://www.youtube.com/channel/UC0URylW_U4i26wN231yRqvA">my channel</a>.</p>
<p>Cheers!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build a Real-time Chat App with React, Node, Socket.io, and HarperDB ]]>
                </title>
                <description>
                    <![CDATA[ In this article, we will be using Socket.io and HarperDB to build a fullstack, real-time chat application with chat rooms.  This will be a great project to learn how to put together fullstack apps, and how to create an app where the backend can commu... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/build-a-realtime-chat-app-with-react-express-socketio-and-harperdb/</link>
                <guid isPermaLink="false">66c8c995e9e57963a5d82ad3</guid>
                
                    <category>
                        <![CDATA[ Chat ]]>
                    </category>
                
                    <category>
                        <![CDATA[ full stack ]]>
                    </category>
                
                    <category>
                        <![CDATA[ node js ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Danny ]]>
                </dc:creator>
                <pubDate>Thu, 04 Aug 2022 15:53:22 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/08/pexels-keira-burton-6146929.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In this article, we will be using Socket.io and HarperDB to build a fullstack, real-time chat application with chat rooms. </p>
<p>This will be a great project to learn how to put together fullstack apps, and how to create an app where the backend can communicate with the frontend in real time.</p>
<p>Normally, using HTTP requests, the server cannot push data to the client in real time. But using Socket.io, the server is able to push real time information to the client about some events that happened on the server.</p>
<p>The app that we'll be building will have two pages:</p>
<p>A join-a-chat-room page:</p>
<p><img src="https://lh6.googleusercontent.com/SyHBvbkVavSJTxNV1nOi2-V_YYXm3upFOJvAzBXwd1VNu10SKV4WBSyQS1tdf4OhiDbqlq3sLqCxWRSJafZwhfcsp72DSKEy3-hk3JvNVGcmsSgkHHpEH69pnBDVKCv6bXiMza4cC4BZiLCOiqKPAIk" alt="How our app home page will look: a form with username input, select room dropdown and Join Room button" width="475" height="468" loading="lazy"></p>
<p>And a chat-room page:</p>
<p><img src="https://lh6.googleusercontent.com/uRkjeHOuGGGf9HnK7bZ1Zd6WeNMo8kaR6Py0_RiEDx1VUuTPx4oYNvfmPlOxNLAicM7bnr9rm0oY0E7k0fwfaZIEz4K1V-5ejOM3ztmrmjIjC8OsRyzNf0HZurxMWUMzdLgic7o8oC-RQxELo8vdcVw" alt="The finished chat page" width="1216" height="678" loading="lazy"></p>
<p>Here's what we'll be using to build this app:</p>
<ul>
<li><strong>Frontend</strong>: <a target="_blank" href="https://reactjs.org/docs/create-a-new-react-app.html">React</a> (A frontend JavaScript framework for building interactive applications)</li>
<li><strong>Backend</strong>: <a target="_blank" href="https://nodejs.org/en/">Node</a> and <a target="_blank" href="https://expressjs.com/">Express</a> (Express is very popular NodeJS framework that allows us to easily create APIs and backends)</li>
<li><strong>Database</strong>: <a target="_blank" href="https://harperdb.io/">HarperDB</a> (a data + application platform that allows you to query data using either SQL or NoSQL. HarperDB also has a built-in API, saving us from having to write a lot of backend code)</li>
<li><strong>Realtime communication</strong>: <a target="_blank" href="https://socket.io/docs/v3/">Socket.io</a> (see below!)</li>
</ul>
<p><a target="_blank" href="https://github.com/DoableDanny/Realtime-chat-app-with-rooms">Here is the source code</a> (remember to give it a star ⭐).</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ol>
<li><a class="post-section-overview" href="#heading-what-is-socketio">What is Socket.io?</a></li>
<li><a class="post-section-overview" href="#heading-project-setup">Project Setup</a></li>
<li><a class="post-section-overview" href="#heading-how-to-build-the-join-a-room-page">How to Build the "Join a Room" Page</a></li>
<li><a class="post-section-overview" href="#heading-how-to-set-up-the-server">How to Set Up the Server</a></li>
<li><a class="post-section-overview" href="#heading-how-to-create-our-first-socketio-event-listener-on-the-server">How to Create our First Socket.io Event Listener on the Server</a></li>
<li><a class="post-section-overview" href="#heading-how-rooms-work-in-socketio">How Rooms Work in Socket.io</a></li>
<li><a class="post-section-overview" href="#heading-how-to-build-the-chat-page">How to Build the Chat Page</a></li>
<li><a class="post-section-overview" href="#heading-how-to-create-the-messages-component-b">How to Create the Messages Component (B)</a></li>
<li><a class="post-section-overview" href="#heading-how-to-create-a-schema-and-table-in-harperdb">How to Create a Schema and Table in HarperDB</a></li>
<li><a class="post-section-overview" href="#heading-how-to-create-the-send-message-component-c">How to Create the Send Message Component (C)</a></li>
<li><a class="post-section-overview" href="#heading-how-to-set-up-harperdb-environment-variables">How to Set Up HarperDB Environment Variables</a></li>
<li><a class="post-section-overview" href="#heading-how-to-allow-users-to-send-messages-to-each-other-with-socketio">How to Allow Users to Send Messages to Each Other with Socket.io</a></li>
<li><a class="post-section-overview" href="#heading-how-to-get-messages-from-harperdb">How to Get Messages from HarperDB</a></li>
<li><a class="post-section-overview" href="#heading-how-to-display-the-last-100-messages-on-the-client">How to Display the Last 100 Messages on the Client</a></li>
<li><a class="post-section-overview" href="#heading-how-to-display-the-room-and-users-a">How to Display the Room and Users (A)</a></li>
<li><a class="post-section-overview" href="#heading-how-to-remove-a-user-from-a-socketio-room">How to Remove a User from a Socket.io Room</a></li>
<li><a class="post-section-overview" href="#heading-how-to-add-the-socketio-disconnect-event-listener">How to Add the Socket.io Disconnect Event Listener</a></li>
</ol>
<h2 id="heading-what-is-socketio">What is Socket.IO?</h2>
<p>Socket.IO allows the server to push information to the client in real time, when events occur on the server.</p>
<p>For example, if you were playing a multiplayer game, an event could be your "friend" scoring a spectacular goal against you.</p>
<p>With Socket.IO, you'd know (almost) instantly about conceding a goal.</p>
<p>Without Socket.IO, the client would have to make multiple polling AJAX calls to verify that the event has occurred on the server. For example, the client could use JavaScript to check for an event on the server every 5 seconds.</p>
<p>Socket.IO means that the client doesn't have to make multiple polling AJAX calls to verify if some event has occurred on the server. Instead, the server sends the info to the client as soon as it gets it. Much better. 👌</p>
<p>So, Socket.IO allows us to easily build real time applications, such as chat apps and multiplayer games.</p>
<h2 id="heading-project-setup">Project Setup</h2>
<h3 id="heading-1-how-to-set-up-our-folders">1. How to set up our folders</h3>
<p>Start a new project in your text editor of choice (VS Code for me), and create two folders at the root called client and server.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/07/folder-structure.JPG" alt="Realtime chat app folder structure" width="600" height="400" loading="lazy"></p>
<p>We will create our frontend React application in the client folder, and our Node/Express backend in the server folder.</p>
<h3 id="heading-2-how-to-install-our-client-dependencies">2. How to install our client dependencies</h3>
<p>Open up a terminal in the root of the project (in VS Code, you can do this by pressing Ctrl+' or by going to <em>terminal</em>-&gt;<em>new terminal</em>)</p>
<p>Next, we will install React into our client directory:</p>
<pre><code class="lang-bash">$ npx create-react-app client
</code></pre>
<p>After React has installed, change directories into the client folder, and install the following dependencies:</p>
<pre><code class="lang-bash">$ <span class="hljs-built_in">cd</span> client
$ npm i react-router-dom socket.io-client
</code></pre>
<p>React-router-dom will allow us to set up routes to our different React components – essentially creating different pages.</p>
<p>Socket.io-client is the client version of socket.io, that allows us to "emit" events to the server. Once received by the server, we can use the server version of socket.io to do stuff like sending messages to users in the same room as the sender, or join a user to a socket room. </p>
<p>You will gain a better understanding of this later when we come to implement these ideas with code.</p>
<h3 id="heading-3-how-to-boot-up-the-react-app">3. How to boot up the React app</h3>
<p>Let's check to make sure everything is working by running the following command from the client directory:</p>
<pre><code class="lang-bash">$ npm start
</code></pre>
<p>Webpack will build the React app and serve it to <a target="_blank" href="http://localhost:3000">http://localhost:3000</a>:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/07/react-is-running.JPG" alt="Create react app up and running on localhost" width="600" height="400" loading="lazy"></p>
<p>Let's now set up our HarperDB database that we will use to permanently save messages sent by users.</p>
<h3 id="heading-how-to-set-up-harperdb">How to set up HarperDB</h3>
<p>First, <a target="_blank" href="https://studio.harperdb.io/">create an account with HarperDB</a>.</p>
<p>Then create a new HarperDB cloud instance:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/harper_instance.JPG" alt="create HarperDB instance" width="600" height="400" loading="lazy"></p>
<p>To make things easy, select the cloud instance:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/instance-type.JPG" alt="select HarperDB instance type" width="600" height="400" loading="lazy"></p>
<p>Select the cloud provider (I chose AWS):</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/cloud_provider.JPG" alt="select HarperDB cloud provider" width="600" height="400" loading="lazy"></p>
<p>Name your cloud instance, and create your instance credentials:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/instance_credentials.JPG" alt="select HarperDB instance credentials" width="600" height="400" loading="lazy"></p>
<p>HarperDB has a generous free tier that we can use for this project, so select that:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/instance_specs.JPG" alt="select HarperDB instance specs" width="600" height="400" loading="lazy"></p>
<p>Check your details are correct, then create the instance.</p>
<p>It will take a few minutes to create the instance, so let's crack on and make our first React component!</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/instance_loading.JPG" alt="HarperDB instance loading" width="600" height="400" loading="lazy"></p>
<h2 id="heading-how-to-build-the-join-a-room-page">How to Build the "Join a Room" Page</h2>
<p>Our homepage is going to end up looking like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/07/home-page.JPG" alt="How our app home page will look: a form with username input, select room dropdown and Join Room button" width="600" height="400" loading="lazy"></p>
<p>The user will enter a username, select a chat room from the dropdown, then click "Join Room". The user will then be taken to the chat room page.</p>
<p>So, let's make this homepage.</p>
<h3 id="heading-1-how-to-create-the-html-form-and-add-styles">1. How to create the HTML form and add styles</h3>
<p>Create a new file at <em>src/pages/home/index.js.</em></p>
<p>We will add basic styling to our app using CSS modules, so create a new file: <em>src/pages/home/styles.module.css</em>.</p>
<p>Our folder structure should now look like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/07/pages-folder-structure.JPG" alt="pages folder with home page component" width="600" height="400" loading="lazy"></p>
<p>Now let's create the basic form HTML:</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// client/src/pages/home/index.js</span>

<span class="hljs-keyword">import</span> styles <span class="hljs-keyword">from</span> <span class="hljs-string">'./styles.module.css'</span>;

<span class="hljs-keyword">const</span> Home = <span class="hljs-function">() =&gt;</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">{styles.container}</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{styles.formContainer}</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>{`<span class="hljs-tag">&lt;&gt;</span>DevRooms<span class="hljs-tag">&lt;/&gt;</span>`}<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{styles.input}</span> <span class="hljs-attr">placeholder</span>=<span class="hljs-string">'Username...'</span> /&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">select</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{styles.input}</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">option</span>&gt;</span>-- Select Room --<span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">'javascript'</span>&gt;</span>JavaScript<span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">'node'</span>&gt;</span>Node<span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">'express'</span>&gt;</span>Express<span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">'react'</span>&gt;</span>React<span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">select</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'btn btn-secondary'</span>&gt;</span>Join Room<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>
    &lt;/div&gt;
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Home;
</code></pre>
<p>Above, we have a simple text input to capture the username, and a select dropdown with some default options for the user to select a chat room to join.</p>
<p>Let's now import this component into App.js, and set up a route for the component using the react-router-dom package. This will be our home page, so the path will just be "/":</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// client/src/App.js</span>

<span class="hljs-keyword">import</span> <span class="hljs-string">'./App.css'</span>;
<span class="hljs-keyword">import</span> { BrowserRouter <span class="hljs-keyword">as</span> Router, Routes, Route } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-router-dom'</span>;
<span class="hljs-keyword">import</span> Home <span class="hljs-keyword">from</span> <span class="hljs-string">'./pages/home'</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Router</span>&gt;</span>
      <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">Routes</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">'/'</span> <span class="hljs-attr">element</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">Home</span> /&gt;</span>} /&gt;
        <span class="hljs-tag">&lt;/<span class="hljs-name">Routes</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">Router</span>&gt;</span></span>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>Now let's add some base styles to make our app look more presentable:</p>
<pre><code class="lang-css"><span class="hljs-comment">/* client/src/App.css */</span>

<span class="hljs-selector-tag">html</span> * {
  <span class="hljs-attribute">font-family</span>: Arial;
  <span class="hljs-attribute">box-sizing</span>: border-box;
}
<span class="hljs-selector-tag">body</span> {
  <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span>;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">0</span>;
  <span class="hljs-attribute">overflow</span>: hidden;
  <span class="hljs-attribute">background</span>: <span class="hljs-built_in">rgb</span>(<span class="hljs-number">63</span>, <span class="hljs-number">73</span>, <span class="hljs-number">204</span>);
}
<span class="hljs-selector-pseudo">::-webkit-scrollbar</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">20px</span>;
}
<span class="hljs-selector-pseudo">::-webkit-scrollbar-track</span> {
  <span class="hljs-attribute">background-color</span>: transparent;
}
<span class="hljs-selector-pseudo">::-webkit-scrollbar-thumb</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#d6dee1</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">20px</span>;
  <span class="hljs-attribute">border</span>: <span class="hljs-number">6px</span> solid transparent;
  <span class="hljs-attribute">background-clip</span>: content-box;
}
<span class="hljs-selector-pseudo">::-webkit-scrollbar-thumb</span><span class="hljs-selector-pseudo">:hover</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#a8bbbf</span>;
}
<span class="hljs-selector-class">.btn</span> {
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">14px</span> <span class="hljs-number">14px</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">6px</span>;
  <span class="hljs-attribute">font-weight</span>: bold;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">1.1rem</span>;
  <span class="hljs-attribute">cursor</span>: pointer;
  <span class="hljs-attribute">border</span>: none;
}
<span class="hljs-selector-class">.btn-outline</span> {
  <span class="hljs-attribute">color</span>: <span class="hljs-built_in">rgb</span>(<span class="hljs-number">153</span>, <span class="hljs-number">217</span>, <span class="hljs-number">234</span>);
  <span class="hljs-attribute">border</span>: <span class="hljs-number">1px</span> solid <span class="hljs-built_in">rgb</span>(<span class="hljs-number">153</span>, <span class="hljs-number">217</span>, <span class="hljs-number">234</span>);
  <span class="hljs-attribute">background</span>: <span class="hljs-built_in">rgb</span>(<span class="hljs-number">63</span>, <span class="hljs-number">73</span>, <span class="hljs-number">204</span>);
}
<span class="hljs-selector-class">.btn-primary</span> {
  <span class="hljs-attribute">background</span>: <span class="hljs-built_in">rgb</span>(<span class="hljs-number">153</span>, <span class="hljs-number">217</span>, <span class="hljs-number">234</span>);
  <span class="hljs-attribute">color</span>: <span class="hljs-built_in">rgb</span>(<span class="hljs-number">0</span>, <span class="hljs-number">24</span>, <span class="hljs-number">111</span>);
}
<span class="hljs-selector-class">.btn-secondary</span> {
  <span class="hljs-attribute">background</span>: <span class="hljs-built_in">rgb</span>(<span class="hljs-number">0</span>, <span class="hljs-number">24</span>, <span class="hljs-number">111</span>);
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#fff</span>;
}
</code></pre>
<p>Let's also add the styles specific to our home page component:</p>
<pre><code class="lang-css"><span class="hljs-comment">/* client/src/pages/home/styles.module.css */</span>

<span class="hljs-selector-class">.container</span> {
  <span class="hljs-attribute">height</span>: <span class="hljs-number">100vh</span>;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</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">background</span>: <span class="hljs-built_in">rgb</span>(<span class="hljs-number">63</span>, <span class="hljs-number">73</span>, <span class="hljs-number">204</span>);
}
<span class="hljs-selector-class">.formContainer</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">400px</span>;
  <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span> auto <span class="hljs-number">0</span> auto;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">32px</span>;
  <span class="hljs-attribute">background</span>: lightblue;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">6px</span>;
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">flex-direction</span>: column;
  <span class="hljs-attribute">align-items</span>: center;
  <span class="hljs-attribute">gap</span>: <span class="hljs-number">28px</span>;
}
<span class="hljs-selector-class">.input</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">12px</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">6px</span>;
  <span class="hljs-attribute">border</span>: <span class="hljs-number">1px</span> solid <span class="hljs-built_in">rgb</span>(<span class="hljs-number">63</span>, <span class="hljs-number">73</span>, <span class="hljs-number">204</span>);
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">0.9rem</span>;
}
<span class="hljs-selector-class">.input</span> <span class="hljs-selector-tag">option</span> {
  <span class="hljs-attribute">margin-top</span>: <span class="hljs-number">20px</span>;
}
</code></pre>
<p>Let's also make the "Join Room" button full width by adding a style attribute:</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// client/src/pages/home/index.js</span>

&lt;button className=<span class="hljs-string">'btn btn-secondary'</span> style={{ <span class="hljs-attr">width</span>: <span class="hljs-string">'100%'</span> }}&gt;Join Room&lt;/button&gt;
</code></pre>
<p>Our home page is now looking solid:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/07/home-page-html.JPG" alt="Fully-styled home page" width="600" height="400" loading="lazy"></p>
<h3 id="heading-2-how-to-add-functionality-to-the-join-room-form">2. How to add functionality to the Join Room form</h3>
<p>Now we have a basic form and styling, so it's time to add some functionality.</p>
<p>Here's what we want to happen when the user clicks the "Join Room" button:</p>
<ol>
<li>Check that the username and room fields are filled in.</li>
<li>If so, we emit a socket event to our server.</li>
<li>Redirect the user to the Chat page (which we will create later).</li>
</ol>
<p>We are going to need to create some state to store <em>username</em> and <em>room</em> values. We also need to create a socket instance.</p>
<p>We could create these states directly within our home component, but our Chat page will also need access to <em>username</em>, <em>room</em> and <em>socket</em>. So we will lift the state up to App.js, where we can then pass these variables down to both the Homepage and Chat page components.</p>
<p>So, let's create our state and set up a socket in App.js, and pass these variables down as props to the  component. We'll also pass the set state functions so we can alter state from :</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// client/src/App.js</span>

<span class="hljs-keyword">import</span> <span class="hljs-string">'./App.css'</span>;
<span class="hljs-keyword">import</span> { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>; <span class="hljs-comment">// Add this</span>
<span class="hljs-keyword">import</span> { BrowserRouter <span class="hljs-keyword">as</span> Router, Routes, Route } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-router-dom'</span>;
<span class="hljs-keyword">import</span> io <span class="hljs-keyword">from</span> <span class="hljs-string">'socket.io-client'</span>; <span class="hljs-comment">// Add this</span>
<span class="hljs-keyword">import</span> Home <span class="hljs-keyword">from</span> <span class="hljs-string">'./pages/home'</span>;

<span class="hljs-keyword">const</span> socket = io.connect(<span class="hljs-string">'http://localhost:4000'</span>); <span class="hljs-comment">// Add this -- our server will run on port 4000, so we connect to it from here</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [username, setUsername] = useState(<span class="hljs-string">''</span>); <span class="hljs-comment">// Add this</span>
  <span class="hljs-keyword">const</span> [room, setRoom] = useState(<span class="hljs-string">''</span>); <span class="hljs-comment">// Add this</span>

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Router</span>&gt;</span>
      <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">Routes</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">Route</span>
            <span class="hljs-attr">path</span>=<span class="hljs-string">'/'</span>
            <span class="hljs-attr">element</span>=<span class="hljs-string">{</span>
              &lt;<span class="hljs-attr">Home</span>
                <span class="hljs-attr">username</span>=<span class="hljs-string">{username}</span> // <span class="hljs-attr">Add</span> <span class="hljs-attr">this</span>
                <span class="hljs-attr">setUsername</span>=<span class="hljs-string">{setUsername}</span> // <span class="hljs-attr">Add</span> <span class="hljs-attr">this</span>
                <span class="hljs-attr">room</span>=<span class="hljs-string">{room}</span> // <span class="hljs-attr">Add</span> <span class="hljs-attr">this</span>
                <span class="hljs-attr">setRoom</span>=<span class="hljs-string">{setRoom}</span> // <span class="hljs-attr">Add</span> <span class="hljs-attr">this</span>
                <span class="hljs-attr">socket</span>=<span class="hljs-string">{socket}</span> // <span class="hljs-attr">Add</span> <span class="hljs-attr">this</span>
              /&gt;</span>
            }
          /&gt;
        <span class="hljs-tag">&lt;/<span class="hljs-name">Routes</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">Router</span>&gt;</span></span>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>We can now access these props in our Home Component. We will use destructuring to get the props:</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// client/src/pages/home/index.js</span>

<span class="hljs-keyword">import</span> styles <span class="hljs-keyword">from</span> <span class="hljs-string">'./style.module.css'</span>;

<span class="hljs-keyword">const</span> Home = <span class="hljs-function">(<span class="hljs-params">{ username, setUsername, room, setRoom, socket }</span>) =&gt;</span> {
  <span class="hljs-keyword">return</span> (
    <span class="hljs-comment">// ...</span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Home;
</code></pre>
<p>When the user types their username or selects a room, we need to update the <em>username</em> and <em>room</em> state variables:</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// client/src/pages/home/index.js</span>

<span class="hljs-comment">// ...</span>

<span class="hljs-keyword">const</span> Home = <span class="hljs-function">(<span class="hljs-params">{ username, setUsername, room, setRoom, socket }</span>) =&gt;</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">{styles.container}</span>&gt;</span>
      // ...
        <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
          <span class="hljs-attr">className</span>=<span class="hljs-string">{styles.input}</span>
          <span class="hljs-attr">placeholder</span>=<span class="hljs-string">'Username...'</span>
          <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setUsername(e.target.value)} // Add this
        /&gt;

        <span class="hljs-tag">&lt;<span class="hljs-name">select</span>
          <span class="hljs-attr">className</span>=<span class="hljs-string">{styles.input}</span>
          <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setRoom(e.target.value)} // Add this
        &gt;
         // ...
        <span class="hljs-tag">&lt;/<span class="hljs-name">select</span>&gt;</span>

        // ...
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Home;
</code></pre>
<p>Now we are capturing the data entered by the user, we can create a <em>joinRoom()</em> callback function for when the user clicks the "Join Room" button:</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// client/src/pages/home/index.js</span>

<span class="hljs-comment">// ...</span>

<span class="hljs-keyword">const</span> Home = <span class="hljs-function">(<span class="hljs-params">{ username, setUsername, room, setRoom, socket }</span>) =&gt;</span> {

  <span class="hljs-comment">// Add this</span>
  <span class="hljs-keyword">const</span> joinRoom = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">if</span> (room !== <span class="hljs-string">''</span> &amp;&amp; username !== <span class="hljs-string">''</span>) {
      socket.emit(<span class="hljs-string">'join_room'</span>, { username, room });
    }
  };

  <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">{styles.container}</span>&gt;</span>
      // ...

        <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
          <span class="hljs-attr">className</span>=<span class="hljs-string">'btn btn-secondary'</span>
          <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">width:</span> '<span class="hljs-attr">100</span>%' }}
          <span class="hljs-attr">onClick</span>=<span class="hljs-string">{joinRoom}</span> // <span class="hljs-attr">Add</span> <span class="hljs-attr">this</span>
        &gt;</span>
          Join Room
        <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>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Home;
</code></pre>
<p>Above, when the user clicks the button, a socket event called _join<em>room</em> is emitted, along with an object containing the user's username and selected room. This event will be received by our server a little later on where we will do some magic.</p>
<p>To finish our home page component, we need to add a redirect at the bottom of our <em>joinRoom()</em> function to take the user to the <em>/chat</em> page:</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// client/src/pages/home/index.js</span>

<span class="hljs-comment">// ...</span>
<span class="hljs-keyword">import</span> { useNavigate } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-router-dom'</span>; <span class="hljs-comment">// Add this</span>

<span class="hljs-keyword">const</span> Home = <span class="hljs-function">(<span class="hljs-params">{ username, setUsername, room, setRoom, socket }</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> navigate = useNavigate(); <span class="hljs-comment">// Add this</span>

  <span class="hljs-keyword">const</span> joinRoom = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">if</span> (room !== <span class="hljs-string">''</span> &amp;&amp; username !== <span class="hljs-string">''</span>) {
      socket.emit(<span class="hljs-string">'join_room'</span>, { username, room });
    }

    <span class="hljs-comment">// Redirect to /chat</span>
    navigate(<span class="hljs-string">'/chat'</span>, { <span class="hljs-attr">replace</span>: <span class="hljs-literal">true</span> }); <span class="hljs-comment">// Add this</span>
  };

 <span class="hljs-comment">// ...</span>
</code></pre>
<p>Test it out: type a username and select a room, then click <em>Join Room</em>. You should be taken to the route <a target="_blank" href="http://localhost:3000/chat">http://localhost:3000/chat</a> – currently an empty page.</p>
<p>But before we create our Chat Page frontend, let's get some stuff running on the server.</p>
<h2 id="heading-how-to-set-up-the-server">How to Set Up the Server</h2>
<p>On the server, we are going to listen out for socket events emitted from the frontend. Currently, we only have a join_room event being emitted from React, so we will add this event listener first.</p>
<p>But before that, we need to install our server dependencies and get the server up and running.</p>
<h3 id="heading-1-how-to-install-the-server-dependencies">1. How to install the server dependencies</h3>
<p>Open up a new terminal (in VS code: Terminal-&gt;New Terminal), change directory into our server folder, initialise a package.json file, and install the following dependencies:</p>
<pre><code class="lang-bash">$ <span class="hljs-built_in">cd</span> server
$ npm init -y
$ npm i axios cors express socket.io dotenv
</code></pre>
<ul>
<li>Axios is a commonly used package to easily make requests to APIs. </li>
<li>Cors allows our client to make requests to other origins – necessary for socket.io to work properly. See <a target="_blank" href="https://medium.com/@electra_chong/what-is-cors-what-is-it-used-for-308cafa4df1a">What is CORS?</a> if you haven't heard of CORS before.</li>
<li>Express is a NodeJS framework that allows us to write our backend more easily with less code.</li>
<li>Socket.io is a library that allows the client and server to communicate in realtime – which isn't possible with standard HTTP requests.</li>
<li>Dotenv is a module that allows us to store private keys and passwords safely, and load them into our code when needed.</li>
</ul>
<p>We will also install nodemon as a dev dependency, so we don't have to restart our server every time we make a change to the code – saving us time and energy:</p>
<pre><code class="lang-bash">$ npm i -D nodemon
</code></pre>
<h3 id="heading-2-how-to-boot-up-our-server">2. How to boot up our server</h3>
<p>Create a folder called index.js in the root of our server directory, and add the following code to get a server up and running:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// server/index.js</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> app = express();
<span class="hljs-keyword">const</span> http = <span class="hljs-built_in">require</span>(<span class="hljs-string">'http'</span>);
<span class="hljs-keyword">const</span> cors = <span class="hljs-built_in">require</span>(<span class="hljs-string">'cors'</span>);

app.use(cors()); <span class="hljs-comment">// Add cors middleware</span>

<span class="hljs-keyword">const</span> server = http.createServer(app);

server.listen(<span class="hljs-number">4000</span>, <span class="hljs-function">() =&gt;</span> <span class="hljs-string">'Server is running on port 4000'</span>);
</code></pre>
<p>Open up the package.json file on our server, and add a script that will allow us to use nodemon in development:</p>
<pre><code class="lang-json">{
  ...
  <span class="hljs-attr">"scripts"</span>: {
    <span class="hljs-attr">"dev"</span>: <span class="hljs-string">"nodemon index.js"</span>
  },
  ...
}
</code></pre>
<p>Now, let's boot up our server by running the following command:</p>
<pre><code class="lang-bash">$ npm run dev
</code></pre>
<p>We can quickly check that our server is running correctly by adding a get request handler:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// server/index.js</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> app = express();
http = <span class="hljs-built_in">require</span>(<span class="hljs-string">'http'</span>);
<span class="hljs-keyword">const</span> cors = <span class="hljs-built_in">require</span>(<span class="hljs-string">'cors'</span>);

app.use(cors()); <span class="hljs-comment">// Add cors middleware</span>

<span class="hljs-keyword">const</span> server = http.createServer(app);

<span class="hljs-comment">// Add this</span>
app.get(<span class="hljs-string">'/'</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  res.send(<span class="hljs-string">'Hello world'</span>);
});

server.listen(<span class="hljs-number">4000</span>, <span class="hljs-function">() =&gt;</span> <span class="hljs-string">'Server is running on port 3000'</span>);
</code></pre>
<p>Now go to <a target="_blank" href="http://localhost:4000/">http://localhost:4000/</a>:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/07/localhost4000.JPG" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Our server is up and running. It's now time to do some server-side Socket.io stuff!</p>
<h2 id="heading-how-to-create-our-first-socketio-event-listener-on-the-server">How to Create our First Socket.io Event Listener on the Server</h2>
<p>Remember when we emitted a _join<em>room</em> event from the client? Well, we are soon going to be listening for that event on the server and adding the user to a socket room.</p>
<p>But first, we need to listen out for when a client connects to the server via socket.io-client.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// server/index.js</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> app = express();
http = <span class="hljs-built_in">require</span>(<span class="hljs-string">'http'</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> { Server } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'socket.io'</span>); <span class="hljs-comment">// Add this</span>

app.use(cors()); <span class="hljs-comment">// Add cors middleware</span>

<span class="hljs-keyword">const</span> server = http.createServer(app); <span class="hljs-comment">// Add this</span>

<span class="hljs-comment">// Add this</span>
<span class="hljs-comment">// Create an io server and allow for CORS from http://localhost:3000 with GET and POST methods</span>
<span class="hljs-keyword">const</span> io = <span class="hljs-keyword">new</span> Server(server, {
  <span class="hljs-attr">cors</span>: {
    <span class="hljs-attr">origin</span>: <span class="hljs-string">'http://localhost:3000'</span>,
    <span class="hljs-attr">methods</span>: [<span class="hljs-string">'GET'</span>, <span class="hljs-string">'POST'</span>],
  },
});

<span class="hljs-comment">// Add this</span>
<span class="hljs-comment">// Listen for when the client connects via socket.io-client</span>
io.on(<span class="hljs-string">'connection'</span>, <span class="hljs-function">(<span class="hljs-params">socket</span>) =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`User connected <span class="hljs-subst">${socket.id}</span>`</span>);

  <span class="hljs-comment">// We can write our socket event listeners in here...</span>
});

server.listen(<span class="hljs-number">4000</span>, <span class="hljs-function">() =&gt;</span> <span class="hljs-string">'Server is running on port 3000'</span>);
</code></pre>
<p>Now, when the client connects from the frontend, the backend captures the connection event, and will log <code>User connected</code> with the unique socket id for that particular client.</p>
<p>Let's test if the server is now capturing the connection event from the client. Go to your React app at <a target="_blank" href="http://localhost:3000/">http://localhost:3000/</a> and refresh the page. </p>
<p>You should see the following log in your server terminal console:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/07/user-connected.JPG" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Awesome, our client has connected to our server via socket.io. Our client and server can now communicate in real time!</p>
<h2 id="heading-how-rooms-work-in-socketio">How Rooms Work in Socket.io</h2>
<p>From the <a target="_blank" href="https://socket.io/docs/v3/rooms/">Socket.io docs</a>:</p>
<blockquote>
<p>"A <em>room</em> is an arbitrary channel that sockets can <code>join</code> and <code>leave</code>. It can be used to broadcast events to a subset of clients."</p>
</blockquote>
<p>So, we can join the user to a room, and then the server can send messages to all users in that room – allowing users to send messages to each other in real time. Cool!</p>
<h3 id="heading-how-to-join-the-user-to-a-socketio-room">How to join the user to a Socket.io room</h3>
<p>Once the user has connected via Socket.io, we can add our socket event listeners on the server to listen for events emitted from the client. Also, we can emit events on the server, and listen for them on the client.</p>
<p>Let's now listen for the _join<em>room</em> event, capture the data (username and room), and add the user to a socket room:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// server/index.js</span>

<span class="hljs-comment">// Listen for when the client connects via socket.io-client</span>
io.on(<span class="hljs-string">'connection'</span>, <span class="hljs-function">(<span class="hljs-params">socket</span>) =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`User connected <span class="hljs-subst">${socket.id}</span>`</span>);

  <span class="hljs-comment">// Add this</span>
  <span class="hljs-comment">// Add a user to a room</span>
  socket.on(<span class="hljs-string">'join_room'</span>, <span class="hljs-function">(<span class="hljs-params">data</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> { username, room } = data; <span class="hljs-comment">// Data sent from client when join_room event emitted</span>
    socket.join(room); <span class="hljs-comment">// Join the user to a socket room</span>
  });
});
</code></pre>
<h3 id="heading-how-to-send-a-message-to-users-in-a-room">How to send a message to users in a room</h3>
<p>Let's now send a message to all users in the room, apart from the user that just joined, to notify them that a new user has joined:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// server/index.js</span>

<span class="hljs-keyword">const</span> CHAT_BOT = <span class="hljs-string">'ChatBot'</span>; <span class="hljs-comment">// Add this</span>
<span class="hljs-comment">// Listen for when the client connects via socket.io-client</span>
io.on(<span class="hljs-string">'connection'</span>, <span class="hljs-function">(<span class="hljs-params">socket</span>) =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`User connected <span class="hljs-subst">${socket.id}</span>`</span>);

  <span class="hljs-comment">// Add a user to a room</span>
  socket.on(<span class="hljs-string">'join_room'</span>, <span class="hljs-function">(<span class="hljs-params">data</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> { username, room } = data; <span class="hljs-comment">// Data sent from client when join_room event emitted</span>
    socket.join(room); <span class="hljs-comment">// Join the user to a socket room</span>

    <span class="hljs-comment">// Add this</span>
    <span class="hljs-keyword">let</span> __createdtime__ = <span class="hljs-built_in">Date</span>.now(); <span class="hljs-comment">// Current timestamp</span>
    <span class="hljs-comment">// Send message to all users currently in the room, apart from the user that just joined</span>
    socket.to(room).emit(<span class="hljs-string">'receive_message'</span>, {
      <span class="hljs-attr">message</span>: <span class="hljs-string">`<span class="hljs-subst">${username}</span> has joined the chat room`</span>,
      <span class="hljs-attr">username</span>: CHAT_BOT,
      __createdtime__,
    });
  });
});
</code></pre>
<p>Above, we are emitting a receive_message event to all clients in the room the current user has just joined, along with some data: the message, username who sent the message, and the time the message was sent.</p>
<p>We will add an event listener in our React application a little later to capture this event, and output the message on the screen.</p>
<p>Let's also send a welcome message to the newly-joined user:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// server/index.js</span>

io.on(<span class="hljs-string">'connection'</span>, <span class="hljs-function">(<span class="hljs-params">socket</span>) =&gt;</span> {
  <span class="hljs-comment">// ...</span>

    <span class="hljs-comment">// Add this</span>
    <span class="hljs-comment">// Send welcome msg to user that just joined chat only</span>
    socket.emit(<span class="hljs-string">'receive_message'</span>, {
      <span class="hljs-attr">message</span>: <span class="hljs-string">`Welcome <span class="hljs-subst">${username}</span>`</span>,
      <span class="hljs-attr">username</span>: CHAT_BOT,
      __createdtime__,
    });
  });
});
</code></pre>
<p>When we add a user to a Socket.io room, Socket.io only stores the socket ids for each user. But we will need the usernames of everyone in the room, as well as the room name. So, let's store that data in variables on the server:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// server/index.js</span>

<span class="hljs-comment">// ...</span>

<span class="hljs-keyword">const</span> CHAT_BOT = <span class="hljs-string">'ChatBot'</span>;
<span class="hljs-comment">// Add this</span>
<span class="hljs-keyword">let</span> chatRoom = <span class="hljs-string">''</span>; <span class="hljs-comment">// E.g. javascript, node,...</span>
<span class="hljs-keyword">let</span> allUsers = []; <span class="hljs-comment">// All users in current chat room</span>

<span class="hljs-comment">// Listen for when the client connects via socket.io-client</span>
io.on(<span class="hljs-string">'connection'</span>, <span class="hljs-function">(<span class="hljs-params">socket</span>) =&gt;</span> {
    <span class="hljs-comment">// ...</span>

    <span class="hljs-comment">// Add this</span>
    <span class="hljs-comment">// Save the new user to the room</span>
    chatRoom = room;
    allUsers.push({ <span class="hljs-attr">id</span>: socket.id, username, room });
    chatRoomUsers = allUsers.filter(<span class="hljs-function">(<span class="hljs-params">user</span>) =&gt;</span> user.room === room);
    socket.to(room).emit(<span class="hljs-string">'chatroom_users'</span>, chatRoomUsers);
    socket.emit(<span class="hljs-string">'chatroom_users'</span>, chatRoomUsers);
  });
});
</code></pre>
<p>Above, we are also sending an array of all the chatRoomUsers back to the client via the _chatroom<em>users</em> event, so we can list all the usernames in the room on the frontend.</p>
<p>Before we add any more code to our server, let's go back to our frontend and create the Chat page – so we can test out if we are receiving the _receive<em>message</em> events. </p>
<h2 id="heading-how-to-build-the-chat-page">How to Build the Chat Page</h2>
<p>In your client folder, create two new files:</p>
<ol>
<li>src/pages/chat/index.js</li>
<li>src/pages/chat/styles.module.css</li>
</ol>
<p>Let's add some styles that we'll use in our chat page and components:</p>
<pre><code class="lang-css"><span class="hljs-comment">/* client/src/pages/chat/styles.module.css */</span>

<span class="hljs-selector-class">.chatContainer</span> {
  <span class="hljs-attribute">max-width</span>: <span class="hljs-number">1100px</span>;
  <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span> auto;
  <span class="hljs-attribute">display</span>: grid;
  <span class="hljs-attribute">grid-template-columns</span>: <span class="hljs-number">1</span>fr <span class="hljs-number">4</span>fr;
  <span class="hljs-attribute">gap</span>: <span class="hljs-number">20px</span>;
}

<span class="hljs-comment">/* Room and users component */</span>
<span class="hljs-selector-class">.roomAndUsersColumn</span> {
  <span class="hljs-attribute">border-right</span>: <span class="hljs-number">1px</span> solid <span class="hljs-number">#dfdfdf</span>;
}
<span class="hljs-selector-class">.roomTitle</span> {
  <span class="hljs-attribute">margin-bottom</span>: <span class="hljs-number">60px</span>;
  <span class="hljs-attribute">text-transform</span>: uppercase;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">2rem</span>;
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#fff</span>;
}
<span class="hljs-selector-class">.usersTitle</span> {
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">1.2rem</span>;
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#fff</span>;
}
<span class="hljs-selector-class">.usersList</span> {
  <span class="hljs-attribute">list-style-type</span>: none;
  <span class="hljs-attribute">padding-left</span>: <span class="hljs-number">0</span>;
  <span class="hljs-attribute">margin-bottom</span>: <span class="hljs-number">60px</span>;
  <span class="hljs-attribute">color</span>: <span class="hljs-built_in">rgb</span>(<span class="hljs-number">153</span>, <span class="hljs-number">217</span>, <span class="hljs-number">234</span>);
}
<span class="hljs-selector-class">.usersList</span> <span class="hljs-selector-tag">li</span> {
  <span class="hljs-attribute">margin-bottom</span>: <span class="hljs-number">12px</span>;
}

<span class="hljs-comment">/* Messages */</span>
<span class="hljs-selector-class">.messagesColumn</span> {
  <span class="hljs-attribute">height</span>: <span class="hljs-number">85vh</span>;
  <span class="hljs-attribute">overflow</span>: auto;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">10px</span> <span class="hljs-number">10px</span> <span class="hljs-number">10px</span> <span class="hljs-number">40px</span>;
}
<span class="hljs-selector-class">.message</span> {
  <span class="hljs-attribute">background</span>: <span class="hljs-built_in">rgb</span>(<span class="hljs-number">0</span>, <span class="hljs-number">24</span>, <span class="hljs-number">111</span>);
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">6px</span>;
  <span class="hljs-attribute">margin-bottom</span>: <span class="hljs-number">24px</span>;
  <span class="hljs-attribute">max-width</span>: <span class="hljs-number">600px</span>;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">12px</span>;
}
<span class="hljs-selector-class">.msgMeta</span> {
  <span class="hljs-attribute">color</span>: <span class="hljs-built_in">rgb</span>(<span class="hljs-number">153</span>, <span class="hljs-number">217</span>, <span class="hljs-number">234</span>);
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">0.75rem</span>;
}
<span class="hljs-selector-class">.msgText</span> {
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#fff</span>;
}

<span class="hljs-comment">/* Message input and button */</span>
<span class="hljs-selector-class">.sendMessageContainer</span> {
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">16px</span> <span class="hljs-number">20px</span> <span class="hljs-number">20px</span> <span class="hljs-number">16px</span>;
}
<span class="hljs-selector-class">.messageInput</span> {
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">14px</span>;
  <span class="hljs-attribute">margin-right</span>: <span class="hljs-number">16px</span>;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">60%</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">6px</span>;
  <span class="hljs-attribute">border</span>: <span class="hljs-number">1px</span> solid <span class="hljs-built_in">rgb</span>(<span class="hljs-number">153</span>, <span class="hljs-number">217</span>, <span class="hljs-number">234</span>);
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">0.9rem</span>;
}
</code></pre>
<p>Now, let's see what our Chat page will end up looking like:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/07/chat-page.JPG" alt="The finished chat page" width="600" height="400" loading="lazy"></p>
<p>Adding all of the code and logic for this page in one file could get confusing and difficult to manage, so let's take advantage of the fact that we are using an awesome frontend framework (React) and <strong>split our page into components</strong>:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/07/image-248.png" alt="The chat page split into three components" width="600" height="400" loading="lazy"></p>
<h3 id="heading-the-chat-page-components">The chat page components:</h3>
<p><strong>A</strong>: Contains the room name, a list of users in that room, and a "Leave" button that removes the user from the room.</p>
<p><strong>B</strong>: The sent messages. Upon initial render, the last 100 messages sent in that room will be fetched from the database and shown to the user.</p>
<p><strong>C</strong>: An input and button to type and send a message.</p>
<p>We will first create component B, so we can display messages to the user.</p>
<h2 id="heading-how-to-create-the-messages-component-b">How to Create the Messages Component (B)</h2>
<p>Create a new file at src/pages/chat/messages.js and add the following code:</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// client/src/pages/chat/messages.js</span>

<span class="hljs-keyword">import</span> styles <span class="hljs-keyword">from</span> <span class="hljs-string">'./styles.module.css'</span>;
<span class="hljs-keyword">import</span> { useState, useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-keyword">const</span> Messages = <span class="hljs-function">(<span class="hljs-params">{ socket }</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> [messagesRecieved, setMessagesReceived] = useState([]);

  <span class="hljs-comment">// Runs whenever a socket event is recieved from the server</span>
  useEffect(<span class="hljs-function">() =&gt;</span> {
    socket.on(<span class="hljs-string">'receive_message'</span>, <span class="hljs-function">(<span class="hljs-params">data</span>) =&gt;</span> {
      <span class="hljs-built_in">console</span>.log(data);
      setMessagesReceived(<span class="hljs-function">(<span class="hljs-params">state</span>) =&gt;</span> [
        ...state,
        {
          <span class="hljs-attr">message</span>: data.message,
          <span class="hljs-attr">username</span>: data.username,
          <span class="hljs-attr">__createdtime__</span>: data.__createdtime__,
        },
      ]);
    });

    <span class="hljs-comment">// Remove event listener on component unmount</span>
    <span class="hljs-keyword">return</span> <span class="hljs-function">() =&gt;</span> socket.off(<span class="hljs-string">'receive_message'</span>);
  }, [socket]);

  <span class="hljs-comment">// dd/mm/yyyy, hh:mm:ss</span>
  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">formatDateFromTimestamp</span>(<span class="hljs-params">timestamp</span>) </span>{
    <span class="hljs-keyword">const</span> date = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(timestamp);
    <span class="hljs-keyword">return</span> date.toLocaleString();
  }

  <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">{styles.messagesColumn}</span>&gt;</span>
      {messagesRecieved.map((msg, i) =&gt; (
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{styles.message}</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{i}</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">display:</span> '<span class="hljs-attr">flex</span>', <span class="hljs-attr">justifyContent:</span> '<span class="hljs-attr">space-between</span>' }}&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{styles.msgMeta}</span>&gt;</span>{msg.username}<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{styles.msgMeta}</span>&gt;</span>
              {formatDateFromTimestamp(msg.__createdtime__)}
            <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">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{styles.msgText}</span>&gt;</span>{msg.message}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">br</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">div</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Messages;
</code></pre>
<p>Above, we have a <em>useEffect</em> hook that runs whenever a socket event is received. We then get the message data passed into the _receive<em>message</em> event listener. From there, we set the <em>messagesReceived</em> state, which is an array of message objects containing the message, username of the sender, and the date the message was sent.</p>
<p>Let's import our new messages component into the Chat page, and then create a route for the Chat page in App.js:</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// client/src/pages/chat/index.js</span>

<span class="hljs-keyword">import</span> styles <span class="hljs-keyword">from</span> <span class="hljs-string">'./styles.module.css'</span>;
<span class="hljs-keyword">import</span> MessagesReceived <span class="hljs-keyword">from</span> <span class="hljs-string">'./messages'</span>;

<span class="hljs-keyword">const</span> Chat = <span class="hljs-function">(<span class="hljs-params">{ socket }</span>) =&gt;</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">{styles.chatContainer}</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">MessagesReceived</span> <span class="hljs-attr">socket</span>=<span class="hljs-string">{socket}</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">div</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Chat;
</code></pre>
<pre><code class="lang-jsx"><span class="hljs-comment">// client/src/App.js</span>

<span class="hljs-keyword">import</span> <span class="hljs-string">'./App.css'</span>;
<span class="hljs-keyword">import</span> { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> Home <span class="hljs-keyword">from</span> <span class="hljs-string">'./pages/home'</span>;
<span class="hljs-keyword">import</span> Chat <span class="hljs-keyword">from</span> <span class="hljs-string">'./pages/chat'</span>;
<span class="hljs-keyword">import</span> { BrowserRouter <span class="hljs-keyword">as</span> Router, Routes, Route } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-router-dom'</span>;
<span class="hljs-keyword">import</span> io <span class="hljs-keyword">from</span> <span class="hljs-string">'socket.io-client'</span>;

<span class="hljs-keyword">const</span> socket = io.connect(<span class="hljs-string">'http://localhost:4000'</span>);

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [username, setUsername] = useState(<span class="hljs-string">''</span>);
  <span class="hljs-keyword">const</span> [room, setRoom] = useState(<span class="hljs-string">''</span>);

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Router</span>&gt;</span>
      <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">Routes</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">Route</span>
            <span class="hljs-attr">path</span>=<span class="hljs-string">'/'</span>
            <span class="hljs-attr">element</span>=<span class="hljs-string">{</span>
              &lt;<span class="hljs-attr">Home</span>
                <span class="hljs-attr">username</span>=<span class="hljs-string">{username}</span>
                <span class="hljs-attr">setUsername</span>=<span class="hljs-string">{setUsername}</span>
                <span class="hljs-attr">room</span>=<span class="hljs-string">{room}</span>
                <span class="hljs-attr">setRoom</span>=<span class="hljs-string">{setRoom}</span>
                <span class="hljs-attr">socket</span>=<span class="hljs-string">{socket}</span>
              /&gt;</span>
            }
          /&gt;
          {/* Add this */}
          <span class="hljs-tag">&lt;<span class="hljs-name">Route</span>
            <span class="hljs-attr">path</span>=<span class="hljs-string">'/chat'</span>
            <span class="hljs-attr">element</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">Chat</span> <span class="hljs-attr">username</span>=<span class="hljs-string">{username}</span> <span class="hljs-attr">room</span>=<span class="hljs-string">{room}</span> <span class="hljs-attr">socket</span>=<span class="hljs-string">{socket}</span> /&gt;</span>}
          /&gt;
        <span class="hljs-tag">&lt;/<span class="hljs-name">Routes</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">Router</span>&gt;</span></span>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>Let's test this out: go to the home page and join a room:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/07/joining-a-room.JPG" alt="Joining a room as Dan" width="600" height="400" loading="lazy"></p>
<p>We should be taken to the Chat page, and receive a welcome message from <em>ChatBot</em>: </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/07/welcome-message.JPG" alt="Welcome message received from ChatBot" width="600" height="400" loading="lazy"></p>
<p>Users can now see the messages they receive. Awesome!</p>
<p>Next up: setting up our database so we can permanently save messages.</p>
<h2 id="heading-how-to-create-a-schema-and-table-in-harperdb">How to Create a Schema and Table in HarperDB</h2>
<p>Go back to your HarperDB dashboard, and click "browse". Then create a new schema called "realtime_chat_app". A schema is simply a group of tables.</p>
<p>Within that schema, create a table called "messages", with a hash attribute of "id".</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/07/image-258.png" alt="Creating our schema and table in HarperDB" width="600" height="400" loading="lazy"></p>
<p>We now have somewhere to store messages, so let's create the SendMessage component.</p>
<h2 id="heading-how-to-create-the-send-message-component-c">How to Create the Send Message Component (C)</h2>
<p>Create the file src/pages/chat/send-message.js and add the following code:</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// client/src/pages/chat/send-message.js</span>

<span class="hljs-keyword">import</span> styles <span class="hljs-keyword">from</span> <span class="hljs-string">'./styles.module.css'</span>;
<span class="hljs-keyword">import</span> React, { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-keyword">const</span> SendMessage = <span class="hljs-function">(<span class="hljs-params">{ socket, username, room }</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> [message, setMessage] = useState(<span class="hljs-string">''</span>);

  <span class="hljs-keyword">const</span> sendMessage = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">if</span> (message !== <span class="hljs-string">''</span>) {
      <span class="hljs-keyword">const</span> __createdtime__ = <span class="hljs-built_in">Date</span>.now();
      <span class="hljs-comment">// Send message to server. We can't specify who we send the message to from the frontend. We can only send to server. Server can then send message to rest of users in room</span>
      socket.emit(<span class="hljs-string">'send_message'</span>, { username, room, message, __createdtime__ });
      setMessage(<span class="hljs-string">''</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">{styles.sendMessageContainer}</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
        <span class="hljs-attr">className</span>=<span class="hljs-string">{styles.messageInput}</span>
        <span class="hljs-attr">placeholder</span>=<span class="hljs-string">'Message...'</span>
        <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setMessage(e.target.value)}
        value={message}
      /&gt;
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'btn btn-primary'</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{sendMessage}</span>&gt;</span>
        Send Message
      <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>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> SendMessage;
</code></pre>
<p>Above, when the user clicks the "Send Message" button, a send_message socket event is emitted to the server, along with a message object. We will handle this event on the server shortly.</p>
<p>Import <em>SendMessage</em> into our Chat page:</p>
<pre><code class="lang-js"><span class="hljs-comment">// src/pages/chat/index.js</span>

<span class="hljs-keyword">import</span> styles <span class="hljs-keyword">from</span> <span class="hljs-string">'./styles.module.css'</span>;
<span class="hljs-keyword">import</span> MessagesReceived <span class="hljs-keyword">from</span> <span class="hljs-string">'./messages'</span>;
<span class="hljs-keyword">import</span> SendMessage <span class="hljs-keyword">from</span> <span class="hljs-string">'./send-message'</span>;

<span class="hljs-keyword">const</span> Chat = <span class="hljs-function">(<span class="hljs-params">{ username, room, socket }</span>) =&gt;</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">{styles.chatContainer}</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">MessagesReceived</span> <span class="hljs-attr">socket</span>=<span class="hljs-string">{socket}</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">SendMessage</span> <span class="hljs-attr">socket</span>=<span class="hljs-string">{socket}</span> <span class="hljs-attr">username</span>=<span class="hljs-string">{username}</span> <span class="hljs-attr">room</span>=<span class="hljs-string">{room}</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">div</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Chat;
</code></pre>
<p>The chat page now looks like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/07/image-259.png" alt="Chat page now has a message input where a message can be typed and sent" width="600" height="400" loading="lazy"></p>
<p>Next we need to set up our HarperDB environment variables so we can start interacting with the database.</p>
<h2 id="heading-how-to-set-up-harperdb-environment-variables">How to Set Up HarperDB Environment Variables</h2>
<p>In order for you to be able to save messages in HarperDB, you'll need your HarperDB instance URL, and your API password. </p>
<p>In your HarperDB dashboard, click on your instance, then go to "config". You will find your instance URL, and your instance API Auth Header – that is, your "super_user" password that allows you to make any request to the database – FOR YOUR EYES ONLY!</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/07/image-263.png" alt="HarperDB instance URL and API auth header" width="600" height="400" loading="lazy"></p>
<p>We will store these variables in a .env file. <strong>Warning: don't push the .env file to GitHub!</strong> This file should not be publicly visible. The variables are loaded in via the server behind the scenes.</p>
<p>Create the following files and add your HarperDB URL and password:</p>
<pre><code class="lang-bash">// server/.env

HARPERDB_URL=<span class="hljs-string">"&lt;your url goes here&gt;"</span>
HARPERDB_PW=<span class="hljs-string">"Basic &lt;your password here&gt;"</span>
</code></pre>
<p>We'll also create a .gitignore file to prevent the .env from being pushed to GitHub, along with the node_modules folder:</p>
<pre><code class="lang-bash">// server/.gitignore

.env
node_modules
</code></pre>
<p>Note: being good with Git and GitHub is a 100% must for all developers. Check out my <a target="_blank" href="https://www.doabledanny.com/git-workflows">Git workflows article</a> if you need to up your Git game.</p>
<p>Or if you find yourself constantly having to look up the same Git commands, and want a quick way to look up, revise, and copy/paste commands -- check out my popular <a target="_blank" href="https://doabledanny.gumroad.com/l/git-commands-cheat-sheet-pdf">Git commands cheat sheet PDF</a> and <a target="_blank" href="https://doabledanny.gumroad.com/l/git-cheat-sheet-poster">physical Git cheat sheet poster</a>.</p>
<p>Finally, let's load our environment variables into our server by adding this code to the top of our main server file:</p>
<pre><code class="lang-js"><span class="hljs-comment">// server/index.js</span>

<span class="hljs-built_in">require</span>(<span class="hljs-string">'dotenv'</span>).config();
<span class="hljs-built_in">console</span>.log(process.env.HARPERDB_URL); <span class="hljs-comment">// remove this after you've confirmed it working</span>
<span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">'express'</span>);
<span class="hljs-comment">// ...</span>
</code></pre>
<h2 id="heading-how-to-allow-users-to-send-messages-to-each-other-with-socketio">How to Allow Users to Send Messages to Each Other with Socket.io</h2>
<p>On the server, we'll listen for the _send<em>message</em> event, then send the message to all users within the room:</p>
<pre><code class="lang-js"><span class="hljs-comment">// server/index.js</span>

<span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">'express'</span>);
<span class="hljs-comment">// ...</span>
<span class="hljs-keyword">const</span> harperSaveMessage = <span class="hljs-built_in">require</span>(<span class="hljs-string">'./services/harper-save-message'</span>); <span class="hljs-comment">// Add this</span>

<span class="hljs-comment">// ...</span>

<span class="hljs-comment">// Listen for when the client connects via socket.io-client</span>
io.on(<span class="hljs-string">'connection'</span>, <span class="hljs-function">(<span class="hljs-params">socket</span>) =&gt;</span> {

  <span class="hljs-comment">// ...</span>

  <span class="hljs-comment">// Add this</span>
  socket.on(<span class="hljs-string">'send_message'</span>, <span class="hljs-function">(<span class="hljs-params">data</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> { message, username, room, __createdtime__ } = data;
    io.in(room).emit(<span class="hljs-string">'receive_message'</span>, data); <span class="hljs-comment">// Send to all users in room, including sender</span>
    harperSaveMessage(message, username, room, __createdtime__) <span class="hljs-comment">// Save message in db</span>
      .then(<span class="hljs-function">(<span class="hljs-params">response</span>) =&gt;</span> <span class="hljs-built_in">console</span>.log(response))
      .catch(<span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> <span class="hljs-built_in">console</span>.log(err));
  });
});

server.listen(<span class="hljs-number">4000</span>, <span class="hljs-function">() =&gt;</span> <span class="hljs-string">'Server is running on port 3000'</span>);
</code></pre>
<p>We now need to create the <em>harperSaveMessage</em> function. Create a new file at server/services/harper-save-message.js, and add the following:</p>
<pre><code class="lang-js"><span class="hljs-comment">// server/services/harper-save-message.js</span>

<span class="hljs-keyword">var</span> axios = <span class="hljs-built_in">require</span>(<span class="hljs-string">'axios'</span>);

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">harperSaveMessage</span>(<span class="hljs-params">message, username, room</span>) </span>{
  <span class="hljs-keyword">const</span> dbUrl = process.env.HARPERDB_URL;
  <span class="hljs-keyword">const</span> dbPw = process.env.HARPERDB_PW;
  <span class="hljs-keyword">if</span> (!dbUrl || !dbPw) <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;

  <span class="hljs-keyword">var</span> data = <span class="hljs-built_in">JSON</span>.stringify({
    <span class="hljs-attr">operation</span>: <span class="hljs-string">'insert'</span>,
    <span class="hljs-attr">schema</span>: <span class="hljs-string">'realtime_chat_app'</span>,
    <span class="hljs-attr">table</span>: <span class="hljs-string">'messages'</span>,
    <span class="hljs-attr">records</span>: [
      {
        message,
        username,
        room,
      },
    ],
  });

  <span class="hljs-keyword">var</span> config = {
    <span class="hljs-attr">method</span>: <span class="hljs-string">'post'</span>,
    <span class="hljs-attr">url</span>: dbUrl,
    <span class="hljs-attr">headers</span>: {
      <span class="hljs-string">'Content-Type'</span>: <span class="hljs-string">'application/json'</span>,
      <span class="hljs-attr">Authorization</span>: dbPw,
    },
    <span class="hljs-attr">data</span>: data,
  };

  <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function">(<span class="hljs-params">resolve, reject</span>) =&gt;</span> {
    axios(config)
      .then(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">response</span>) </span>{
        resolve(<span class="hljs-built_in">JSON</span>.stringify(response.data));
      })
      .catch(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">error</span>) </span>{
        reject(error);
      });
  });
}

<span class="hljs-built_in">module</span>.exports = harperSaveMessage;
</code></pre>
<p>Above, saving the data may take a little time, so we are returning a promise which will be resolved if the data saves successfully, or rejected if not.</p>
<p>If you're wondering where I got the above code, HarperDB provides an awesome "<a target="_blank" href="https://studio.harperdb.io/resources/examples/QuickStart%20Examples/Create%20dev%20Schema">code examples</a>" section in their studio dashboard, which makes life much easier:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/07/image-265.png" alt="HarperDB code examples" width="600" height="400" loading="lazy"></p>
<p>Time to test! Join a room as a user, then send a message. Then go to HarperDB and click on "browse", then click on the "messages" table. You should see your message in the database:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/07/image-264.png" alt="Our first messages in the database" width="600" height="400" loading="lazy"></p>
<p>Cool 😎. So what next? Well, it'd be great if the last 100 messages sent in the room were loaded when a user joins a room, wouldn't it?</p>
<h2 id="heading-how-to-get-messages-from-harperdb">How to Get Messages from HarperDB</h2>
<p>On the server, let's create a function that fetches the last 100 messages sent in a particular room (notice how HarperDB also allows us to use SQL queries 👌):</p>
<pre><code class="lang-js"><span class="hljs-comment">// server/services/harper-get-messages.js</span>

<span class="hljs-keyword">let</span> axios = <span class="hljs-built_in">require</span>(<span class="hljs-string">'axios'</span>);

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">harperGetMessages</span>(<span class="hljs-params">room</span>) </span>{
  <span class="hljs-keyword">const</span> dbUrl = process.env.HARPERDB_URL;
  <span class="hljs-keyword">const</span> dbPw = process.env.HARPERDB_PW;
  <span class="hljs-keyword">if</span> (!dbUrl || !dbPw) <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;

  <span class="hljs-keyword">let</span> data = <span class="hljs-built_in">JSON</span>.stringify({
    <span class="hljs-attr">operation</span>: <span class="hljs-string">'sql'</span>,
    <span class="hljs-attr">sql</span>: <span class="hljs-string">`SELECT * FROM realtime_chat_app.messages WHERE room = '<span class="hljs-subst">${room}</span>' LIMIT 100`</span>,
  });

  <span class="hljs-keyword">let</span> config = {
    <span class="hljs-attr">method</span>: <span class="hljs-string">'post'</span>,
    <span class="hljs-attr">url</span>: dbUrl,
    <span class="hljs-attr">headers</span>: {
      <span class="hljs-string">'Content-Type'</span>: <span class="hljs-string">'application/json'</span>,
      <span class="hljs-attr">Authorization</span>: dbPw,
    },
    <span class="hljs-attr">data</span>: data,
  };

  <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function">(<span class="hljs-params">resolve, reject</span>) =&gt;</span> {
    axios(config)
      .then(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">response</span>) </span>{
        resolve(<span class="hljs-built_in">JSON</span>.stringify(response.data));
      })
      .catch(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">error</span>) </span>{
        reject(error);
      });
  });
}

<span class="hljs-built_in">module</span>.exports = harperGetMessages;
</code></pre>
<p>We'll call this function whenever a user joins a room:</p>
<pre><code class="lang-js"><span class="hljs-comment">// server/index.js</span>

<span class="hljs-comment">// ...</span>
<span class="hljs-keyword">const</span> harperSaveMessage = <span class="hljs-built_in">require</span>(<span class="hljs-string">'./services/harper-save-message'</span>);
<span class="hljs-keyword">const</span> harperGetMessages = <span class="hljs-built_in">require</span>(<span class="hljs-string">'./services/harper-get-messages'</span>); <span class="hljs-comment">// Add this</span>

<span class="hljs-comment">// ...</span>

<span class="hljs-comment">// Listen for when the client connects via socket.io-client</span>
io.on(<span class="hljs-string">'connection'</span>, <span class="hljs-function">(<span class="hljs-params">socket</span>) =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`User connected <span class="hljs-subst">${socket.id}</span>`</span>);

  <span class="hljs-comment">// Add a user to a room</span>
  socket.on(<span class="hljs-string">'join_room'</span>, <span class="hljs-function">(<span class="hljs-params">data</span>) =&gt;</span> {

    <span class="hljs-comment">// ...</span>

    <span class="hljs-comment">// Add this</span>
    <span class="hljs-comment">// Get last 100 messages sent in the chat room</span>
    harperGetMessages(room)
      .then(<span class="hljs-function">(<span class="hljs-params">last100Messages</span>) =&gt;</span> {
        <span class="hljs-comment">// console.log('latest messages', last100Messages);</span>
        socket.emit(<span class="hljs-string">'last_100_messages'</span>, last100Messages);
      })
      .catch(<span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> <span class="hljs-built_in">console</span>.log(err));
  });

 <span class="hljs-comment">// ...</span>
</code></pre>
<p>Above, if the messages are fetched successfully, we emit a Socket.io event called _last_100<em>messages</em>. We'll now listen for this event on the frontend.</p>
<h2 id="heading-how-to-display-the-last-100-messages-on-the-client">How to Display the Last 100 Messages on the Client</h2>
<p>Below, we add a useEffect hook that contains a Socket.io event listener for the _last_100<em>messages</em> event<em>.</em> From there, the messages are sorted in date order, with most recent at the bottom, and the <em>messagesReceived</em> state is updated.</p>
<p>When <em>messagesReceived</em> is updated, a useEffect runs to scroll the <em>messageColumn</em> div to the most recent message. This improves the user experience of our app 👍.</p>
<pre><code class="lang-js"><span class="hljs-comment">// client/src/pages/chat/messages.js</span>

<span class="hljs-keyword">import</span> styles <span class="hljs-keyword">from</span> <span class="hljs-string">'./styles.module.css'</span>;
<span class="hljs-keyword">import</span> { useState, useEffect, useRef } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-keyword">const</span> Messages = <span class="hljs-function">(<span class="hljs-params">{ socket }</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> [messagesRecieved, setMessagesReceived] = useState([]);

  <span class="hljs-keyword">const</span> messagesColumnRef = useRef(<span class="hljs-literal">null</span>); <span class="hljs-comment">// Add this</span>

  <span class="hljs-comment">// Runs whenever a socket event is recieved from the server</span>
  useEffect(<span class="hljs-function">() =&gt;</span> {
    socket.on(<span class="hljs-string">'receive_message'</span>, <span class="hljs-function">(<span class="hljs-params">data</span>) =&gt;</span> {
      <span class="hljs-built_in">console</span>.log(data);
      setMessagesReceived(<span class="hljs-function">(<span class="hljs-params">state</span>) =&gt;</span> [
        ...state,
        {
          <span class="hljs-attr">message</span>: data.message,
          <span class="hljs-attr">username</span>: data.username,
          <span class="hljs-attr">__createdtime__</span>: data.__createdtime__,
        },
      ]);
    });

    <span class="hljs-comment">// Remove event listener on component unmount</span>
    <span class="hljs-keyword">return</span> <span class="hljs-function">() =&gt;</span> socket.off(<span class="hljs-string">'receive_message'</span>);
  }, [socket]);

  <span class="hljs-comment">// Add this</span>
  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-comment">// Last 100 messages sent in the chat room (fetched from the db in backend)</span>
    socket.on(<span class="hljs-string">'last_100_messages'</span>, <span class="hljs-function">(<span class="hljs-params">last100Messages</span>) =&gt;</span> {
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Last 100 messages:'</span>, <span class="hljs-built_in">JSON</span>.parse(last100Messages));
      last100Messages = <span class="hljs-built_in">JSON</span>.parse(last100Messages);
      <span class="hljs-comment">// Sort these messages by __createdtime__</span>
      last100Messages = sortMessagesByDate(last100Messages);
      setMessagesReceived(<span class="hljs-function">(<span class="hljs-params">state</span>) =&gt;</span> [...last100Messages, ...state]);
    });

    <span class="hljs-keyword">return</span> <span class="hljs-function">() =&gt;</span> socket.off(<span class="hljs-string">'last_100_messages'</span>);
  }, [socket]);

  <span class="hljs-comment">// Add this</span>
  <span class="hljs-comment">// Scroll to the most recent message</span>
  useEffect(<span class="hljs-function">() =&gt;</span> {
    messagesColumnRef.current.scrollTop =
      messagesColumnRef.current.scrollHeight;
  }, [messagesRecieved]);

  <span class="hljs-comment">// Add this</span>
  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">sortMessagesByDate</span>(<span class="hljs-params">messages</span>) </span>{
    <span class="hljs-keyword">return</span> messages.sort(
      <span class="hljs-function">(<span class="hljs-params">a, b</span>) =&gt;</span> <span class="hljs-built_in">parseInt</span>(a.__createdtime__) - <span class="hljs-built_in">parseInt</span>(b.__createdtime__)
    );
  }

  <span class="hljs-comment">// dd/mm/yyyy, hh:mm:ss</span>
  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">formatDateFromTimestamp</span>(<span class="hljs-params">timestamp</span>) </span>{
    <span class="hljs-keyword">const</span> date = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(timestamp);
    <span class="hljs-keyword">return</span> date.toLocaleString();
  }

  <span class="hljs-keyword">return</span> (
    <span class="hljs-comment">// Add ref to this div</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">{styles.messagesColumn}</span> <span class="hljs-attr">ref</span>=<span class="hljs-string">{messagesColumnRef}</span>&gt;</span>
      {messagesRecieved.map((msg, i) =&gt; (
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{styles.message}</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{i}</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">display:</span> '<span class="hljs-attr">flex</span>', <span class="hljs-attr">justifyContent:</span> '<span class="hljs-attr">space-between</span>' }}&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{styles.msgMeta}</span>&gt;</span>{msg.username}<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{styles.msgMeta}</span>&gt;</span>
              {formatDateFromTimestamp(msg.__createdtime__)}
            <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">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{styles.msgText}</span>&gt;</span>{msg.message}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">br</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">div</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Messages;
</code></pre>
<h2 id="heading-how-to-display-the-room-and-users-a">How to Display the Room and Users (A)</h2>
<p>We've made components B and C, so let's finish things off by making A.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/07/image-248.png" alt="The chat page split into three components" width="600" height="400" loading="lazy"></p>
<p>On the server, when a user joins a room, we emit a _chatroom<em>users</em> event that sends all of the users in the room to all clients in that room. Let's listen for that event in a component called <em>RoomAndUsers.</em></p>
<p>Below, there's also a "Leave" button that, when pressed, causes the emission of a _leave<em>room</em> event to the server. It then redirects the user back to the Home page.</p>
<pre><code class="lang-js"><span class="hljs-comment">// client/src/pages/chat/room-and-users.js</span>

<span class="hljs-keyword">import</span> styles <span class="hljs-keyword">from</span> <span class="hljs-string">'./styles.module.css'</span>;
<span class="hljs-keyword">import</span> { useState, useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> { useNavigate } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-router-dom'</span>;

<span class="hljs-keyword">const</span> RoomAndUsers = <span class="hljs-function">(<span class="hljs-params">{ socket, username, room }</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> [roomUsers, setRoomUsers] = useState([]);

  <span class="hljs-keyword">const</span> navigate = useNavigate();

  useEffect(<span class="hljs-function">() =&gt;</span> {
    socket.on(<span class="hljs-string">'chatroom_users'</span>, <span class="hljs-function">(<span class="hljs-params">data</span>) =&gt;</span> {
      <span class="hljs-built_in">console</span>.log(data);
      setRoomUsers(data);
    });

    <span class="hljs-keyword">return</span> <span class="hljs-function">() =&gt;</span> socket.off(<span class="hljs-string">'chatroom_users'</span>);
  }, [socket]);

  <span class="hljs-keyword">const</span> leaveRoom = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> __createdtime__ = <span class="hljs-built_in">Date</span>.now();
    socket.emit(<span class="hljs-string">'leave_room'</span>, { username, room, __createdtime__ });
    <span class="hljs-comment">// Redirect to home page</span>
    navigate(<span class="hljs-string">'/'</span>, { <span class="hljs-attr">replace</span>: <span class="hljs-literal">true</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">{styles.roomAndUsersColumn}</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{styles.roomTitle}</span>&gt;</span>{room}<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>

      <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
        {roomUsers.length &gt; 0 &amp;&amp; <span class="hljs-tag">&lt;<span class="hljs-name">h5</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{styles.usersTitle}</span>&gt;</span>Users:<span class="hljs-tag">&lt;/<span class="hljs-name">h5</span>&gt;</span>}
        <span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{styles.usersList}</span>&gt;</span>
          {roomUsers.map((user) =&gt; (
            <span class="hljs-tag">&lt;<span class="hljs-name">li</span>
              <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span>
                <span class="hljs-attr">fontWeight:</span> `${<span class="hljs-attr">user.username</span> === <span class="hljs-string">username</span> ? '<span class="hljs-attr">bold</span>' <span class="hljs-attr">:</span> '<span class="hljs-attr">normal</span>'}`,
              }}
              <span class="hljs-attr">key</span>=<span class="hljs-string">{user.id}</span>
            &gt;</span>
              {user.username}
            <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
          ))}
        <span class="hljs-tag">&lt;/<span class="hljs-name">ul</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">className</span>=<span class="hljs-string">'btn btn-outline'</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{leaveRoom}</span>&gt;</span>
        Leave
      <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>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> RoomAndUsers;
</code></pre>
<p>Let's import this component into the Chat page:</p>
<pre><code class="lang-js"><span class="hljs-comment">// client/src/pages/chat/index.js</span>

<span class="hljs-keyword">import</span> styles <span class="hljs-keyword">from</span> <span class="hljs-string">'./styles.module.css'</span>;
<span class="hljs-keyword">import</span> RoomAndUsersColumn <span class="hljs-keyword">from</span> <span class="hljs-string">'./room-and-users'</span>; <span class="hljs-comment">// Add this</span>
<span class="hljs-keyword">import</span> SendMessage <span class="hljs-keyword">from</span> <span class="hljs-string">'./send-message'</span>;
<span class="hljs-keyword">import</span> MessagesReceived <span class="hljs-keyword">from</span> <span class="hljs-string">'./messages'</span>;

<span class="hljs-keyword">const</span> Chat = <span class="hljs-function">(<span class="hljs-params">{ username, room, socket }</span>) =&gt;</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">{styles.chatContainer}</span>&gt;</span>
      {/* Add this */}
      <span class="hljs-tag">&lt;<span class="hljs-name">RoomAndUsersColumn</span> <span class="hljs-attr">socket</span>=<span class="hljs-string">{socket}</span> <span class="hljs-attr">username</span>=<span class="hljs-string">{username}</span> <span class="hljs-attr">room</span>=<span class="hljs-string">{room}</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">MessagesReceived</span> <span class="hljs-attr">socket</span>=<span class="hljs-string">{socket}</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">SendMessage</span> <span class="hljs-attr">socket</span>=<span class="hljs-string">{socket}</span> <span class="hljs-attr">username</span>=<span class="hljs-string">{username}</span> <span class="hljs-attr">room</span>=<span class="hljs-string">{room}</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">div</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Chat;
</code></pre>
<h2 id="heading-how-to-remove-a-user-from-a-socketio-room">How to Remove a User from a Socket.io Room</h2>
<p>Socket.io provides a <em>leave()</em> method that you can use to remove a user from a Socket.io room. We are also keeping track of our users in an array on server memory, so we'll remove the user from this array too:</p>
<pre><code class="lang-js"><span class="hljs-comment">// server/index.js</span>

<span class="hljs-keyword">const</span> leaveRoom = <span class="hljs-built_in">require</span>(<span class="hljs-string">'./utils/leave-room'</span>); <span class="hljs-comment">// Add this</span>

<span class="hljs-comment">// ...</span>

<span class="hljs-comment">// Listen for when the client connects via socket.io-client</span>
io.on(<span class="hljs-string">'connection'</span>, <span class="hljs-function">(<span class="hljs-params">socket</span>) =&gt;</span> {

  <span class="hljs-comment">// ...</span>

  <span class="hljs-comment">// Add this</span>
  socket.on(<span class="hljs-string">'leave_room'</span>, <span class="hljs-function">(<span class="hljs-params">data</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> { username, room } = data;
    socket.leave(room);
    <span class="hljs-keyword">const</span> __createdtime__ = <span class="hljs-built_in">Date</span>.now();
    <span class="hljs-comment">// Remove user from memory</span>
    allUsers = leaveRoom(socket.id, allUsers);
    socket.to(room).emit(<span class="hljs-string">'chatroom_users'</span>, allUsers);
    socket.to(room).emit(<span class="hljs-string">'receive_message'</span>, {
      <span class="hljs-attr">username</span>: CHAT_BOT,
      <span class="hljs-attr">message</span>: <span class="hljs-string">`<span class="hljs-subst">${username}</span> has left the chat`</span>,
      __createdtime__,
    });
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`<span class="hljs-subst">${username}</span> has left the chat`</span>);
  });
});

server.listen(<span class="hljs-number">4000</span>, <span class="hljs-function">() =&gt;</span> <span class="hljs-string">'Server is running on port 3000'</span>);
</code></pre>
<p>We now need to create the <em>leaveRoom()</em> function:</p>
<pre><code class="lang-js"><span class="hljs-comment">// server/utils/leave-room.js</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">leaveRoom</span>(<span class="hljs-params">userID, chatRoomUsers</span>) </span>{
  <span class="hljs-keyword">return</span> chatRoomUsers.filter(<span class="hljs-function">(<span class="hljs-params">user</span>) =&gt;</span> user.id != userID);
}

<span class="hljs-built_in">module</span>.exports = leaveRoom;
</code></pre>
<p>Why put this short function in a separate utils folder, you ask? Because we'll be using it again later on and we don't want to repeat ourselves (keeping our code <a target="_blank" href="https://en.wikipedia.org/wiki/Don%27t_repeat_yourself">DRY</a>).</p>
<p>Let's test things out: open up two windows side-by-side, and join the chat on both:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/07/image-266.png" alt="Two windows chatting in realtime." width="600" height="400" loading="lazy"></p>
<p>Then click the leave button on window 2:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/07/image-267.png" alt="The user is removed from the chat when they click the Leave button" width="600" height="400" loading="lazy"></p>
<p>The user is removed from the chat, and a message is sent to the other users – notifying them that they've left. Nice!</p>
<h2 id="heading-how-to-add-the-socketio-disconnect-event-listener">How to Add the Socket.io Disconnect Event Listener</h2>
<p>What if the user is somehow disconnected from the server, like if their internet drops? Socket.io provides a built-in <em>disconnect</em> event listener for this. Let's add that into our server to remove a user from memory when they disconnect:</p>
<pre><code class="lang-js"><span class="hljs-comment">// server/index.js</span>

<span class="hljs-comment">// ...</span>

<span class="hljs-comment">// Listen for when the client connects via socket.io-client</span>
io.on(<span class="hljs-string">'connection'</span>, <span class="hljs-function">(<span class="hljs-params">socket</span>) =&gt;</span> {

  <span class="hljs-comment">// ...</span>

  <span class="hljs-comment">// Add this</span>
  socket.on(<span class="hljs-string">'disconnect'</span>, <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'User disconnected from the chat'</span>);
    <span class="hljs-keyword">const</span> user = allUsers.find(<span class="hljs-function">(<span class="hljs-params">user</span>) =&gt;</span> user.id == socket.id);
    <span class="hljs-keyword">if</span> (user?.username) {
      allUsers = leaveRoom(socket.id, allUsers);
      socket.to(chatRoom).emit(<span class="hljs-string">'chatroom_users'</span>, allUsers);
      socket.to(chatRoom).emit(<span class="hljs-string">'receive_message'</span>, {
        <span class="hljs-attr">message</span>: <span class="hljs-string">`<span class="hljs-subst">${user.username}</span> has disconnected from the chat.`</span>,
      });
    }
  });
});

server.listen(<span class="hljs-number">4000</span>, <span class="hljs-function">() =&gt;</span> <span class="hljs-string">'Server is running on port 3000'</span>);
</code></pre>
<p>And there you have it – you've just built a fullstack realtime chat application with a React frontend, a Node/Express backend, and a HarperDB database. Nice job!</p>
<p>Next time, I plan to check out HarperDB’s <a target="_blank" href="https://harperdb.io/docs/custom-functions/">Custom Functions</a>, which enable users to define their own API endpoints within HarperDB. This means that we can build our entire application in one place! See an example of how HarperDB is collapsing the stack <a target="_blank" href="https://harperdb.io/blog/mean-stack-alternative/">in this article</a>.</p>
<h2 id="heading-a-challenge-for-you">A challenge for you 💪</h2>
<p>If you refresh the Chat page, the user's username and room will be lost. See if you can prevent this info from being lost when the user refreshes the page. Clue: <a target="_blank" href="https://www.w3schools.com/html/html5_webstorage.asp">local storage</a> could be useful!</p>
<h2 id="heading-thank-you-for-reading"><strong>Thank you for reading!</strong></h2>
<p>If you found this article useful, you can:</p>
<ul>
<li><a target="_blank" href="https://www.youtube.com/channel/UC0URylW_U4i26wN231yRqvA">Subscribe to my YouTube channel</a>. I will be uploading in-depth tutorials and project videos on React/NextJS/Node/Express.</li>
<li><a target="_blank" href="https://twitter.com/doabledanny">Follow me on Twitter</a> where I tweet about my freelancing journey, side projects, and current learnings.</li>
<li><a target="_blank" href="https://doabledanny.gumroad.com/">Checkout my Gumroad store</a> where I make useful and popular (8000 downloads as of writing) cheatsheets and posters.</li>
<li><a target="_blank" href="https://www.doabledanny.com/blog/">Checkout my web dev blog</a></li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ NextJS and HarperDB Tutorial –Build a Full Stack Productivity Timer App ]]>
                </title>
                <description>
                    <![CDATA[ Building full stack applications can be tough. You have to think about frontend, APIs, databases, authentication - and how all of these things work together.  So, in this article, I'll show you how to do all of those things using NextJS and HarperDB.... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/nextjs-and-harperdb-tutorial-build-a-full-stack-app/</link>
                <guid isPermaLink="false">66c8c99cc4cede4e0083f740</guid>
                
                    <category>
                        <![CDATA[ full stack ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Next.js ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Danny ]]>
                </dc:creator>
                <pubDate>Fri, 01 Apr 2022 16:25:42 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/03/feature.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Building full stack applications can be tough. You have to think about frontend, APIs, databases, authentication - and how all of these things work together. </p>
<p>So, in this article, I'll show you how to do all of those things using NextJS and HarperDB.</p>
<p>We'll be building a full stack task timer app that includes JSON Web Token Authentication, fetching data using HarperDB's built-in API, and rendering the data with NextJS. We will also make use of NextJS's API.</p>
<p>If you're wondering what HarperDB is, it's a database-as-a-service that allows you to query data using either SQL or NoSQL. HarperDB also has a built-in API, saving us from having to write a lot of backend code.</p>
<p><a target="_blank" href="https://next-js-harper-db-task-timer.vercel.app/">Here is what we'll be building</a>.</p>
<p><a target="_blank" href="https://github.com/DoableDanny/NextJS-HarperDB-Task-Timer">Here is the source code</a> (remember to give it a star ⭐).</p>
<h2 id="heading-contents">Contents</h2>
<ul>
<li><a class="post-section-overview" href="#heading-setup">Setup</a></li>
<li><a class="post-section-overview" href="#heading-create-a-layout-component-to-wrap-every-page">Create the Layout component</a></li>
<li><a class="post-section-overview" href="#heading-create-some-reusable-components">Create some reusable components</a></li>
<li><a class="post-section-overview" href="#heading-create-the-signup-page">Create the Signup Page</a></li>
<li><a class="post-section-overview" href="#heading-how-to-log-out-the-user">How to log out the user</a></li>
<li><a class="post-section-overview" href="#heading-the-login-page">The Login Page</a></li>
<li><a class="post-section-overview" href="#heading-create-a-tasks-context">Create a Tasks Context</a></li>
<li><a class="post-section-overview" href="#heading-create-the-task-timer-page">Create the Task Timer Page</a></li>
<li><a class="post-section-overview" href="#heading-create-the-addselect-taskbar">Create the Add/Select Task Bar</a></li>
<li><a class="post-section-overview" href="#heading-the-stats-page">Create the Stats Page</a></li>
</ul>
<h2 id="heading-setup">Setup</h2>
<h3 id="heading-1-install-nextjs-with-typescript">1. Install NextJS with TypeScript:</h3>
<pre><code class="lang-bash">npx create-next-app@latest --ts
</code></pre>
<p>You’ll then be asked for a project name. I’m calling it “task timer”.</p>
<p>We can then change to the project directory:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> “task timer”
</code></pre>
<h3 id="heading-2-install-and-set-up-tailwindcss">2. Install and set up TailwindCSS</h3>
<p>We'll be styling this project with <a target="_blank" href="https://tailwindcss.com/">Tailwind</a>, so let's install everything we'll need.</p>
<p>Install TailwindCSS and its peer dependencies via npm, and then run the init command to generate both tailwind.config.js and postcss.config.js:</p>
<pre><code class="lang-bash">npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
</code></pre>
<p>Add the paths to all of your React component files in your tailwind.config.js file:</p>
<pre><code class="lang-js"><span class="hljs-built_in">module</span>.exports = {
  <span class="hljs-attr">content</span>: [
    <span class="hljs-string">"./src/pages/**/*.{js,ts,jsx,tsx}"</span>,
    <span class="hljs-string">"./src/components/**/*.{js,ts,jsx,tsx}"</span>,
  ],
  <span class="hljs-attr">theme</span>: {
    <span class="hljs-attr">extend</span>: {},
  },
  <span class="hljs-attr">plugins</span>: [],
}
</code></pre>
<p>Next, create a <code>src</code> folder in the project root, and drag the <code>styles</code> and <code>pages</code> folders into <code>src</code>. In <code>styles/global.css</code>, add the following Tailwind directives to bring in the Tailwind classes:</p>
<pre><code class="lang-css"><span class="hljs-keyword">@tailwind</span> base;
<span class="hljs-keyword">@tailwind</span> components;
<span class="hljs-keyword">@tailwind</span> utilities;
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/tailwind.JPG" alt="tailwind directives" width="600" height="400" loading="lazy"></p>
<p>Our NextJS project is now set up and ready to use with Tailwind.</p>
<p>Let's clear out our <code>src/pages/index.tsx</code> page, and add the following:</p>
<pre><code class="lang-tsx">import type { NextPage } from "next"

const Home: NextPage = () =&gt; {
  return (
    &lt;div&gt;
      &lt;h1 className="text-red-500"&gt;Hello World&lt;/h1&gt;
    &lt;/div&gt;
  )
}

export default Home
</code></pre>
<p>Run the build process and start the dev server with:</p>
<pre><code class="lang-bash">npm run dev
</code></pre>
<p>Our server will now be running on http://localhost:3000</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/hello_world.JPG" alt="Hello world" width="600" height="400" loading="lazy"></p>
<h3 id="heading-3-set-up-harperdb">3. Set up HarperDB</h3>
<p>First, <a target="_blank" href="https://studio.harperdb.io/">create an account with HarperDB</a>.</p>
<p>Then create a new HarperDB cloud instance:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/harper_instance.JPG" alt="create HarperDB instance" width="600" height="400" loading="lazy"></p>
<p>To make things easy, select the cloud instance:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/instance-type.JPG" alt="select HarperDB instance type" width="600" height="400" loading="lazy"></p>
<p>Select the cloud provider (I chose AWS):</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/cloud_provider.JPG" alt="select HarperDB cloud provider" width="600" height="400" loading="lazy"></p>
<p>Name your cloud instance, and create your instance credentials:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/instance_credentials.JPG" alt="select HarperDB instance credentials" width="600" height="400" loading="lazy"></p>
<p>HarperDB has a generous free tier that we can use for this project, so select that:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/instance_specs.JPG" alt="select HarperDB instance specs" width="600" height="400" loading="lazy"></p>
<p>Check your details are correct, then create the instance.</p>
<p>It will take a few minutes to create the instance, so let's crack on and make the UI for our app!</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/instance_loading.JPG" alt="HarperDB instance loading" width="600" height="400" loading="lazy"></p>
<h2 id="heading-create-a-layout-component-to-wrap-every-page">Create a Layout Component to Wrap Every Page</h2>
<p>Create the folder <code>src/components</code>. In here, we will create components that can be reused throughout the project.</p>
<p>First, let's create a file to hold any constants that will be used through our app, such as the site title. It's helpful to keep a single source of truth for values like this, so that if we want to change them, we only have to change them in one place.</p>
<pre><code class="lang-tsx">// src/constants/constants.ts

export const SITE_TITLE = "Super Simple Task Timer"
</code></pre>
<p>Let's now create our navbar:</p>
<pre><code class="lang-tsx">// src/components/layout/Navbar.tsx

import Link from "next/link"
import { SITE_TITLE } from "../../constants/constants"

const Navbar = () =&gt; {
  return (
    &lt;header className="flex justify-between items-center bg-green-600 text-white py-4 px-4"&gt;
      &lt;h2 className="text-lg"&gt;
        &lt;Link href="/"&gt;
          &lt;a&gt;{SITE_TITLE}&lt;/a&gt;
        &lt;/Link&gt;
      &lt;/h2&gt;
      &lt;nav&gt;
        &lt;ul className="flex"&gt;
          &lt;NavLink href="/login"&gt;Login&lt;/NavLink&gt;
          &lt;NavLink href="/signup"&gt;Signup&lt;/NavLink&gt;
        &lt;/ul&gt;
      &lt;/nav&gt;
    &lt;/header&gt;
  )
}

interface NavLinkProps {
  href: string
  children: string
}

const NavLink: React.FC&lt;NavLinkProps&gt; = ({ href, children }) =&gt; {
  return (
    &lt;li className="ml-8"&gt;
      &lt;Link href={href}&gt;
        &lt;a&gt;{children}&lt;/a&gt;
      &lt;/Link&gt;
    &lt;/li&gt;
  )
}

export default Navbar
</code></pre>
<p>Create the footer:</p>
<pre><code class="lang-tsx">// src/components/layout/Footer.tsx

import { SITE_TITLE } from "../../constants/constants"

const Footer = () =&gt; {
  return (
    &lt;footer className="bg-green-600 text-white text-center py-4"&gt;
      &lt;p className="mb-1"&gt;{SITE_TITLE} &amp;copy;&lt;/p&gt;
      &lt;p&gt;Designed &amp; developed by Danny Adams&lt;/p&gt;
    &lt;/footer&gt;
  )
}

export default Footer
</code></pre>
<p>Now we can create our layout component to wrap every page. Using flex-grow on the <code>&lt;main&gt;</code> tag ensures that the page content takes up all available space between the header and footer.</p>
<pre><code class="lang-tsx">// src/components/layout/Layout.tsx

import Navbar from "./Navbar"
import Footer from "./Footer"

const Layout: React.FC = ({ children }) =&gt; {
  return (
    &lt;div className="min-h-screen flex flex-col"&gt;
      &lt;Navbar /&gt;
      &lt;main className="flex flex-col grow"&gt;{children}&lt;/main&gt;
      &lt;div className="mt-auto"&gt;
        &lt;Footer /&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  )
}

export default Layout
</code></pre>
<p>Then, in <code>src/pages/_app.tsx</code>, we can wrap every page component with <code>Layout</code>:</p>
<pre><code class="lang-tsx">import "../styles/globals.css"
import type { AppProps } from "next/app"
import Layout from "../components/layout/Layout"

function MyApp({ Component, pageProps }: AppProps) {
  return (
    &lt;Layout&gt;
      &lt;Component {...pageProps} /&gt;
    &lt;/Layout&gt;
  )
}

export default MyApp
</code></pre>
<p>And there we go! Every page now has a navbar, content area that takes up 100% of available space, and a footer that always sits at the bottom.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/layout.JPG" alt="Layout component" width="600" height="400" loading="lazy"></p>
<h2 id="heading-create-some-reusable-components">Create Some Reusable Components</h2>
<p>We will now create some basic components that can be reused throughout the project.</p>
<p>Create a button component:</p>
<pre><code class="lang-tsx">// src/components/Button.tsx

interface Props {
  children: React.ReactNode
  color: "primary" | "success" | "secondary" | "warning" | "danger"
  handleClick?: () =&gt; void
  type?: "button" | "submit"
  extraClasses?: string
}

const Button: React.FC&lt;Props&gt; = ({
  children,
  color,
  handleClick,
  type,
  extraClasses,
}) =&gt; {
  let colors: string
  switch (color) {
    case "primary":
      colors = "bg-blue-500 hover:bg-blue-600"
      break
    case "success":
      colors = "bg-green-500 hover:bg-green-600"
      break
    case "warning":
      colors = "bg-yellow-300 hover:bg-yellow-400 text-black"
      break
    case "secondary":
      colors = "bg-pink-500 hover:bg-pink-600"
      break
    default:
      colors = "bg-red-500 hover:bg-red-600"
  }
  const classes = `rounded text-white py-2 px-4 ${colors} ${extraClasses}`

  return (
    &lt;button className={classes} onClick={handleClick} type={type}&gt;
      {children}
    &lt;/button&gt;
  )
}

export default Button
</code></pre>
<p>Create a link component that uses NextJS Link to automatically prefetch pages it links to in the background - making page loads quickly:</p>
<pre><code class="lang-tsx">// src/components/Link.tsx

import NextLink from "next/link"

interface Props {
  href: string
  children: React.ReactNode
}

const Link = ({ href, children }: Props) =&gt; {
  return (
    &lt;NextLink href={href}&gt;
      &lt;a className="underline underline-offset-1 text-blue-700"&gt;{children}&lt;/a&gt;
    &lt;/NextLink&gt;
  )
}

export default Link
</code></pre>
<p>Let's also create an <code>Alert</code> component to display alert messages, for example if a user enters invalid form data, a red error message will be displayed:</p>
<pre><code class="lang-tsx">// src/components/Alert.tsx

interface Props {
  children: React.ReactNode
  type: "success" | "warning" | "danger"
  key?: number
  extraClasses?: string
}
const Alert = ({ children, type, key, extraClasses }: Props) =&gt; {
  let color
  switch (type) {
    case "success":
      color = "bg-blue-500"
      break
    case "warning":
      color = "bg-yellow-300 text-yellow-800"
      break
    default:
      color = "bg-red-500"
  }
  const classes = `text-white text-center p-2 rounded mt-4 ${color} ${extraClasses}`

  return (
    &lt;div key={key} className={classes}&gt;
      {children}
    &lt;/div&gt;
  )
}

export default Alert
</code></pre>
<p>Create a main page heading component:</p>
<pre><code class="lang-tsx">// src/components/PageHeading.tsx

interface Props {
  extraClasses: string
}

const PageHeading: React.FC&lt;Props&gt; = ({ children, extraClasses }) =&gt; {
  const classes = "text-4xl text-green-900 font-semibold " + extraClasses

  return &lt;h1 className={classes}&gt;{children}&lt;/h1&gt;
}

export default PageHeading
</code></pre>
<p>Let's also create a component to reuse through our login and signup forms that contains a label and an input:</p>
<pre><code class="lang-tsx">// src/components/Form.tsx

interface InputProps {
  inputType: "text" | "email" | "password"
  inputName: string
  handleChange: (e: React.ChangeEvent&lt;HTMLInputElement&gt;) =&gt; void
  value: string
}

interface LabelAndInputProps extends InputProps {
  label: string
}

export const LabelAndInput: React.FC&lt;LabelAndInputProps&gt; = ({
  label,
  inputType,
  inputName,
  handleChange,
  value,
}) =&gt; {
  return (
    &lt;div className="flex flex-col mb-2"&gt;
      &lt;label htmlFor="name"&gt;{label}&lt;/label&gt;
      &lt;Input
        inputType={inputType}
        inputName={inputName}
        handleChange={handleChange}
        value={value}
      /&gt;
    &lt;/div&gt;
  )
}

export const Input: React.FC&lt;InputProps&gt; = ({
  inputType,
  inputName,
  handleChange,
  value,
}) =&gt; {
  return (
    &lt;input
      className="px-3 py-2 border-gray-200 border-2 rounded"
      type={inputType}
      name={inputName}
      id={inputName}
      onChange={handleChange}
      value={value}
    /&gt;
  )
}
</code></pre>
<h2 id="heading-create-the-signup-page">Create the Signup Page</h2>
<p><a target="_blank" href="https://next-js-harper-db-task-timer.vercel.app/signup">Here is what the signup page will look like</a>.</p>
<h3 id="heading-signup-page-ui">Signup page UI</h3>
<p>First, let's create a signup form component at the location <code>src/components/signup-page/SignupForm.tsx</code>:</p>
<pre><code class="lang-tsx">// src/components/signup-page/SignupForm.tsx

import { useState } from "react"
import { LabelAndInput } from "../Form"
import Button from "../Button"

const SignupForm = () =&gt; {
  const [username, setUsername] = useState("")
  const [password1, setPassword1] = useState("")
  const [password2, setPassword2] = useState("")

  return (
    &lt;form className="w-full sm:w-96"&gt;
      &lt;LabelAndInput
        label="Username"
        inputType="text"
        inputName="username"
        handleChange={e =&gt; setUsername(e.target.value)}
        value={username}
      /&gt;
      &lt;LabelAndInput
        label="Password"
        inputType="password"
        inputName="password1"
        handleChange={e =&gt; setPassword1(e.target.value)}
        value={password1}
      /&gt;
      &lt;LabelAndInput
        label="Confirm password"
        inputType="password"
        inputName="password2"
        handleChange={e =&gt; setPassword2(e.target.value)}
        value={password2}
      /&gt;
      &lt;Button
        color="success"
        type="submit"
        extraClasses="w-full mt-3 py-3 font-semibold"
      &gt;
        Create Account
      &lt;/Button&gt;
    &lt;/form&gt;
  )
}

export default SignupForm
</code></pre>
<p>We can create the signup page at <code>src/pages/signup.tsx</code> and import the above form:</p>
<pre><code class="lang-tsx">// src/pages/signup.tsx

import type { NextPage } from "next"
import SignupForm from "../components/signup-page/SignupForm"
import PageHeading from "../components/PageHeading"

const Signup: NextPage = () =&gt; {
  return (
    &lt;div className="mx-auto mt-20"&gt;
      &lt;PageHeading extraClasses="text-center mb-8"&gt;
        Create an account
      &lt;/PageHeading&gt;
      &lt;SignupForm /&gt;
    &lt;/div&gt;
  )
}

export default Signup
</code></pre>
<p>Our signup page UI is now complete:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/signup_page.JPG" alt="Signup page UI" width="600" height="400" loading="lazy"></p>
<h3 id="heading-signup-page-logic">Signup page logic</h3>
<p>Back in our <code>SignupForm</code> component, add a <code>handleSubmit</code> callback function to be called when then form is submitted:</p>
<pre><code class="lang-tsx">// src/components/signup-page/SignupForm.tsx

&lt;form className='w-full sm:w-96' onSubmit={handleSubmit}&gt;
</code></pre>
<p>In the <code>handleSubmit</code> function, we'll need to post the form data to our NextJS API. Our API will then forward this data on to HarperDB to create a new user in our HarperDB database.</p>
<p>Let's first write the beginning of our <code>handleSubmit</code> function:</p>
<pre><code class="lang-tsx">// src/components/signup-page/SignupForm.tsx

// ...
import { postFormData } from "../../utils/postFormData"

const SignupForm = () =&gt; {
  // ...

  const handleSubmit = async (e: React.FormEvent) =&gt; {
    e.preventDefault();

    const formData = { username, password1, password2 };
    const { response, result } = await postFormData(formData, '/api/signup');

    console.log({ response, result });
  };
</code></pre>
<p>Now create a <code>src/utils</code> folder, and define a utility function that takes any data object and an API route, then returns the response and result:</p>
<pre><code class="lang-tsx">// src/utils/postFormData.ts

export const postFormData = async (data: { [k: string]: any }, url: string) =&gt; {
  const requestOptions: RequestInit = {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
    },
    body: JSON.stringify(data),
  }
  const response = await fetch(url, requestOptions)
  const result = await response.json()
  return { response, result }
}
</code></pre>
<p>We need to create our first API route at <code>src/pages/api/signup</code>.</p>
<p>But before we do that, we will install the <code>next-connect</code> package, which allows us to write our APIs with expressJS-like syntax, and saves us some time with error handling:</p>
<pre><code class="lang-bash">npm install next-connect
</code></pre>
<p>Create a file at <code>src/middleware/_defaultHandler.ts</code>, and add the following:</p>
<pre><code class="lang-tsx">// src/middleware/_defaultHandler.ts

import { NextApiRequest, NextApiResponse } from "next"
import nextConnect from "next-connect"

// This middleware function will run between every request and api handler
const handler = nextConnect&lt;NextApiRequest, NextApiResponse&gt;({
  onError: (err, req, res) =&gt; {
    res.status(501).json({ error: `Something went wrong! ${err.message}` })
  },
  onNoMatch: (req, res) =&gt; {
    res.status(405).json({ error: `Method ${req.method} Not Allowed` })
  },
})

export default handler
</code></pre>
<p>The above middleware function will run with every API request, and handle any request errors.</p>
<p>We can now create our API route at <code>src/pages/api/signup</code>. First, let's check for any errors in the posted form data, and send back an array of error messages to the client if so:</p>
<pre><code class="lang-tsx">// src/pages/api/signup

import type { NextApiRequest, NextApiResponse } from "next"
import handler from "../../middleware/_defaultHandler"

export default handler.post(
  async (req: NextApiRequest, res: NextApiResponse) =&gt; {
    const { username, password1, password2 } = req.body

    const errors: string[] = getFormErrors(username, password1, password2)
    if (errors.length &gt; 0) {
      return res.status(400).json({ error: errors })
    }
  }
)

const getFormErrors = (
  username: string,
  password1: string,
  password2: string
) =&gt; {
  const errors: string[] = []
  if (!username || !password1 || !password2) {
    errors.push("All fields are required")
  }
  if (password1.length &lt; 6) {
    errors.push("Password must be at least 6 characters")
  }
  if (password1 !== password2) {
    errors.push("Passwords do not match")
  }
  return errors
}
</code></pre>
<p>Now, if we post some incorrect form data from the frontend, we get error messages logged to the console:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/bad_request.JPG" alt="Bad form data" width="600" height="400" loading="lazy"></p>
<p>Once we know the form data is legit, we need to post it to the HarperDB API, which will create a new user for us. Let's write a function that will do this.</p>
<p>First, we need our HarperDB instance URL. If you click on your instance, then go to "config", you will find your instance URL, and your instance API Auth Header – that is, your "super_user" password that allows you to make any request to the database – FOR YOUR EYES ONLY!</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/instance_auth.JPG" alt="Instance info" width="600" height="400" loading="lazy"></p>
<p>We will be needing the instance URL on both frontend and backend, so let's store it in our constants file:</p>
<pre><code class="lang-ts"><span class="hljs-comment">// src/constants/constants.ts</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> SITE_TITLE = <span class="hljs-string">"Super Simple Task Timer"</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> DB_URL = <span class="hljs-string">"Your_HDB_URL_Here"</span>
</code></pre>
<p>Our password must be kept secret, so it should never be available on the frontend. Our password will be loaded into the server as an environment variable. Add your password to <code>.env.local</code> in your project root:</p>
<pre><code class="lang-bash">HARPERDB_PW=Basic yourpasswordgoeshere
</code></pre>
<p>HarperDB lists all of the operations that can be performed by category in the "example code" tab:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/harper_code_examples.JPG" alt="harperdb code examples" width="600" height="400" loading="lazy"></p>
<p>We want to use the HarperDB "add_user" operation, so let's create our own function to do just that:</p>
<pre><code class="lang-ts"><span class="hljs-comment">// src/utils/harperdb/createNewUser.ts</span>

<span class="hljs-keyword">import</span> { DB_URL } <span class="hljs-keyword">from</span> <span class="hljs-string">"../../constants/constants"</span>

<span class="hljs-comment">// This function can only be ran on the backend as it requires a "super_user" password</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> harperCreateNewUser = <span class="hljs-keyword">async</span> (
  username: <span class="hljs-built_in">string</span>,
  password: <span class="hljs-built_in">string</span>
) =&gt; {
  <span class="hljs-keyword">const</span> DB_PW = process.env.HARPERDB_PW
  <span class="hljs-keyword">if</span> (!DB_URL || !DB_PW) {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Error: .env variables are undefined"</span>)
    <span class="hljs-keyword">throw</span> <span class="hljs-string">"Internal server error"</span>
  }
  <span class="hljs-keyword">const</span> myHeaders = <span class="hljs-keyword">new</span> Headers()
  myHeaders.append(<span class="hljs-string">"Content-Type"</span>, <span class="hljs-string">"application/json"</span>)
  myHeaders.append(<span class="hljs-string">"Authorization"</span>, DB_PW)
  <span class="hljs-keyword">const</span> raw = <span class="hljs-built_in">JSON</span>.stringify({
    operation: <span class="hljs-string">"add_user"</span>,
    role: <span class="hljs-string">"standard_user"</span>,
    username: username.toLowerCase(),
    password: password,
    active: <span class="hljs-literal">true</span>,
  })
  <span class="hljs-keyword">const</span> requestOptions: RequestInit = {
    method: <span class="hljs-string">"POST"</span>,
    headers: myHeaders,
    body: raw,
    redirect: <span class="hljs-string">"follow"</span>,
  }

  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(DB_URL, requestOptions)
  <span class="hljs-keyword">const</span> result = <span class="hljs-keyword">await</span> response.json()
  <span class="hljs-keyword">return</span> { response, result }
}
</code></pre>
<p>Notice how the "role" is "standard_user". If we gave everyone that created an account a "super_user" role, then anybody would be able to delete your tables and wreak havoc on our database! </p>
<p>Let's now set up this "standard_user" role, and make the tables we will need.</p>
<p>Create a scheme called "productivity_timer" (a schema is a group of tables). In this schema, create a table called "tasks" with hash attribute (each entries unique key) "id":</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/harper_make_tables.JPG" alt="Create a HarperDB table" width="600" height="400" loading="lazy"></p>
<p>We now need to create the "standard_user" role to limit the access that our users will have. Go to "roles", and create a standard role called "standard_user". Then change all the tasks table access permissions to true:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/user_roles.JPG" alt="HarperDB user roles" width="600" height="400" loading="lazy"></p>
<p>Let's also add some tasks to our table that we can fetch into our application later:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/add_to_db.JPG" alt="Add data" width="600" height="400" loading="lazy"></p>
<p>Add the following JSON to add some tasks:</p>
<pre><code class="lang-json">[
  { <span class="hljs-attr">"username"</span>: <span class="hljs-string">"dan"</span>, <span class="hljs-attr">"task_name"</span>: <span class="hljs-string">"make header"</span>, <span class="hljs-attr">"time_in_seconds"</span>: <span class="hljs-number">0</span> },
  { <span class="hljs-attr">"username"</span>: <span class="hljs-string">"dan"</span>, <span class="hljs-attr">"task_name"</span>: <span class="hljs-string">"make footer"</span>, <span class="hljs-attr">"time_in_seconds"</span>: <span class="hljs-number">0</span> },
  { <span class="hljs-attr">"username"</span>: <span class="hljs-string">"sally"</span>, <span class="hljs-attr">"task_name"</span>: <span class="hljs-string">"learn NextJS"</span>, <span class="hljs-attr">"time_in_seconds"</span>: <span class="hljs-number">0</span> }
]
</code></pre>
<p>Back to our API route at <code>src/pages/api/signup</code>, we can now add the code to create a new user in HarperDB:</p>
<pre><code class="lang-ts"><span class="hljs-comment">// src/pages/api/signup</span>

<span class="hljs-keyword">import</span> <span class="hljs-keyword">type</span> { NextApiRequest, NextApiResponse } <span class="hljs-keyword">from</span> <span class="hljs-string">"next"</span>
<span class="hljs-keyword">import</span> handler <span class="hljs-keyword">from</span> <span class="hljs-string">"../../middleware/_defaultHandler"</span>
<span class="hljs-keyword">import</span> { harperCreateNewUser } <span class="hljs-keyword">from</span> <span class="hljs-string">"../../utils/harperdb/createNewUser"</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> handler.post(
  <span class="hljs-keyword">async</span> (req: NextApiRequest, res: NextApiResponse) =&gt; {
    <span class="hljs-keyword">const</span> { username, password1, password2 } = req.body

    <span class="hljs-keyword">const</span> errors: <span class="hljs-built_in">string</span>[] = getFormErrors(username, password1, password2)
    <span class="hljs-keyword">if</span> (errors.length &gt; <span class="hljs-number">0</span>) {
      <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">400</span>).json({ error: errors })
    }

    <span class="hljs-comment">// Create new user with HarperDB, and send back result</span>
    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">const</span> { response, result } = <span class="hljs-keyword">await</span> harperCreateNewUser(
        username,
        password1
      )
      <span class="hljs-keyword">return</span> res.status(response.status).json(result)
    } <span class="hljs-keyword">catch</span> (err) {
      <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">500</span>).json({ error: err })
    }
  }
)
</code></pre>
<p>To test creating a new user, you will now need to stop the dev server with "ctrl + c", then restart with <code>npm run dev</code> – in order to load in the .env variables.</p>
<p>Go to the signup page, fill in the form, and submit. WOOHOO! We have created our first user!</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/created_user.JPG" alt="Created a new user" width="600" height="400" loading="lazy"></p>
<p>And if we look in the users table on HarperDB, we see that the new user was added successfully:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/new_user.JPG" alt="New user in table" width="600" height="400" loading="lazy"></p>
<p>Now, back on the frontend, we need to handle the response and result that is sent back from the server. </p>
<p>If the response status code sent back from the server is not 200, we know that something went wrong. So we can set the errors in a state variable, and return from <code>handleSubmit</code> early:</p>
<pre><code class="lang-tsx">// src/components/signup-page/SignupForm.tsx

const [errors, setErrors] = useState&lt;string | string[]&gt;("")

const handleSubmit = async (e: React.FormEvent) =&gt; {
  e.preventDefault()
  setErrors("")

  const formData = { username, password1, password2 }
  const { response, result } = await postFormData(formData, "/api/signup")

  // Account not created successfully
  if (response.status !== 200) {
    setErrors(result.error)
    return
  }
}
</code></pre>
<p>Let's display these errors at the bottom of the form:</p>
<pre><code class="lang-tsx">// src/components/signup-page/SignupForm.tsx

// ...
import Alert from "../Alert"

const SignupForm = () =&gt; {
  // ...
  const [errors, setErrors] = useState&lt;string | string[]&gt;("")

  // ...

  const displayErrors = () =&gt; {
    if (errors.length === 0) return

    return typeof errors === "string" ? (
      &lt;Alert type="danger"&gt;{errors}&lt;/Alert&gt;
    ) : (
      errors.map((err, i) =&gt; (
        &lt;Alert key={i} type="danger"&gt;
          {err}
        &lt;/Alert&gt;
      ))
    )
  }

  return (
    &lt;form className="w-full sm:w-96" onSubmit={handleSubmit}&gt;
      {/* form stuff... */}

      {displayErrors()}
    &lt;/form&gt;
  )
}

export default SignupForm
</code></pre>
<p>Now if the user enters invalid form data, errors will be displayed:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/invalid_form.JPG" alt="Invalid form data" width="600" height="400" loading="lazy"></p>
<p>And if the user already exists, HarperDB will send us an appropriate error message:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/user_exists.JPG" alt="User already exists" width="600" height="400" loading="lazy"></p>
<p>Nice!</p>
<p>But if the response status code is 200, then we know that the account was created successfully. So, we can get the user a JSON Web Token (JWT) which will be used to authenticate the user and allow them to access protected routes.</p>
<h3 id="heading-how-to-get-the-user-a-json-web-token">How to get the user a JSON Web Token</h3>
<p>HarperDB can create JWTs for each user in the database, meaning we don't have to install any packages and handle the logic ourselves - nice!</p>
<p>How will our JWT auth work? When HarperDB sends back a JWT to the frontend, we will save the JWT in localStorage in the browser. Then, every time the user makes a request, we will get the JWT from localStorage and attach it to the request header. HarperDB will automatically check if there is a JWT in the request header, and check that it is valid. If so, it will go ahead with the request.</p>
<p>But first, we need to create a User context using React's context API so that the user's username is available throughout the whole of the app.</p>
<pre><code class="lang-ts"><span class="hljs-comment">// src/contexts/UserContext.ts</span>

<span class="hljs-keyword">import</span> { createContext } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> UserContext = createContext({
  username: <span class="hljs-string">""</span>,
  setUsername: <span class="hljs-function">(<span class="hljs-params">username: <span class="hljs-built_in">string</span></span>) =&gt;</span> {},
})
</code></pre>
<p>We then need to wrap our whole application in the <code>UserContext.Provider</code>, so <code>username</code> and <code>setUsername</code> are available on every page. Initially, <code>username</code> will be an empty string.</p>
<pre><code class="lang-tsx">// src/pages/_app.tsx

import { useState } from "react"
// ...
import { UserContext } from "../contexts/UserContext"

function MyApp({ Component, pageProps }: AppProps) {
  const [username, setUsername] = useState("")

  return (
    &lt;UserContext.Provider value={{ username, setUsername }}&gt;
      &lt;Layout&gt;
        &lt;Component {...pageProps} /&gt;
      &lt;/Layout&gt;
    &lt;/UserContext.Provider&gt;
  )
}

export default MyApp
</code></pre>
<p>Let's now write a function that will fetch JWTs from HarperDB. HarperDB will check that the username and password are correct, then create the JWTs from the username, and send them back to our app:</p>
<pre><code class="lang-ts"><span class="hljs-comment">// src/utils/harperdb/fetchJWTTokens.ts</span>

<span class="hljs-keyword">import</span> { DB_URL } <span class="hljs-keyword">from</span> <span class="hljs-string">"../../constants/constants"</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> harperFetchJWTTokens = <span class="hljs-keyword">async</span> (
  username: <span class="hljs-built_in">string</span>,
  password: <span class="hljs-built_in">string</span>
) =&gt; {
  <span class="hljs-keyword">if</span> (!DB_URL) {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Error: DB_URL undefined"</span>)
    <span class="hljs-keyword">throw</span> <span class="hljs-string">"Internal server error"</span>
  }

  <span class="hljs-keyword">const</span> myHeaders = <span class="hljs-keyword">new</span> Headers()
  myHeaders.append(<span class="hljs-string">"Content-Type"</span>, <span class="hljs-string">"application/json"</span>)

  <span class="hljs-keyword">const</span> raw = <span class="hljs-built_in">JSON</span>.stringify({
    operation: <span class="hljs-string">"create_authentication_tokens"</span>,
    username: username,
    password: password,
  })

  <span class="hljs-keyword">const</span> requestOptions: RequestInit = {
    method: <span class="hljs-string">"POST"</span>,
    headers: myHeaders,
    body: raw,
    redirect: <span class="hljs-string">"follow"</span>,
  }

  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(DB_URL, requestOptions)
  <span class="hljs-keyword">const</span> result = <span class="hljs-keyword">await</span> response.json()
  <span class="hljs-keyword">return</span> { response, result }
}
</code></pre>
<p>Back to <code>SignupForm.tsx</code>, we need to fetch the JWTs using the above function, check if HarperDB created and sent them back successfully, and if so authenticate the user:</p>
<pre><code class="lang-tsx">// src/components/signup-page/SignupForm.tsx

import { useState, useContext } from "react"
import { UserContext } from "../../contexts/UserContext"
import { useRouter } from "next/router"
import { harperFetchJWTTokens } from "../../utils/harperdb/fetchJWTTokens"
// ...

const SignupForm = () =&gt; {
  //...

  const user = useContext(UserContext)
  const router = useRouter()

  const handleSubmit = async (e: React.FormEvent) =&gt; {
    // ...

    // Account created successfully; get JWTs
    try {
      const { response, result } = await harperFetchJWTTokens(
        username,
        password1
      )
      const accessToken = result.operation_token
      if (response.status === 200 &amp;&amp; accessToken) {
        authenticateUser(username, accessToken)
      } else {
        // Account created, but failed to get JWTs
        // Redirect to login page
        router.push("/login")
      }
    } catch (err) {
      console.log(err)
      setErrors("Whoops, something went wrong :(")
    }
  }

  const authenticateUser = (username: string, accessToken: string) =&gt; {
    user.setUsername(username)
    localStorage.setItem("access_token", accessToken)
  }

  // ...
}

export default SignupForm
</code></pre>
<p>Above, if HarperDB sends back the operation token successfully, we save it to localStorage so it can be used to authenticate the user for as long as the JWT hasn't expired, and set the username in context.</p>
<p>Let's test this out. When we create a new user we should get an access token stored in localStorage. Create a new user, open your chrome dev tools, then under "Application" you should see the access token.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/access_token.JPG" alt="Access token in localStorage" width="600" height="400" loading="lazy"></p>
<p>Awesome!</p>
<p>In <code>src/pages/signup.tsx</code>, let's render a different component depending on if the username is set:</p>
<pre><code class="lang-tsx">// src/pages/signup.tsx

import { useContext } from "react"
import { UserContext } from "../contexts/UserContext"
import Alert from "../components/Alert"
// ...

const Signup: NextPage = () =&gt; {
  const { username } = useContext(UserContext)

  return (
    &lt;div className="mx-auto mt-20"&gt;
      {username ? (
        &lt;Alert type="success"&gt;You are logged in as {username}&lt;/Alert&gt;
      ) : (
        &lt;&gt;
          &lt;PageHeading extraClasses="text-center mb-8"&gt;
            Create an account
          &lt;/PageHeading&gt;
          &lt;SignupForm /&gt;
        &lt;/&gt;
      )}
    &lt;/div&gt;
  )
}

export default Signup
</code></pre>
<p>Now when we create an account, we get this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/logged_in.JPG" alt="Logged in alert" width="600" height="400" loading="lazy"></p>
<p>But we have a problem: context doesn't keep the username when we refresh the page, meaning when we refresh the page, the signup form will be displayed again, even though the user is logged in.</p>
<p>To solve this problem, we can create a custom hook called <code>useUser</code>.</p>
<h3 id="heading-creating-a-useuser-custom-hook">Creating a useUser custom hook</h3>
<p>The <code>useUser</code> hook will run once every time the user goes to a new page, or refreshes the current page. </p>
<p>Let's first create the hook. We will also move <code>username</code> and <code>setUsername</code> into this hook to keep things organized.</p>
<pre><code class="lang-ts"><span class="hljs-comment">// src/custom-hooks/useUser.ts</span>

<span class="hljs-keyword">import</span> { useState, useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>
<span class="hljs-keyword">import</span> { harperGetUsername } <span class="hljs-keyword">from</span> <span class="hljs-string">"../utils/harperdb/getUsername"</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> useUser = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> [username, setUsername] = useState(<span class="hljs-string">""</span>)

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-comment">// User is logged in</span>
    <span class="hljs-keyword">if</span> (username) <span class="hljs-keyword">return</span>

    <span class="hljs-comment">// Check for access token and try to log user in</span>
    <span class="hljs-keyword">const</span> accessToken = <span class="hljs-built_in">localStorage</span>.getItem(<span class="hljs-string">"access_token"</span>)
    <span class="hljs-keyword">if</span> (accessToken) {
      tryLogUserIn(accessToken)
    }

    <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">tryLogUserIn</span>(<span class="hljs-params">accessToken: <span class="hljs-built_in">string</span></span>) </span>{
      <span class="hljs-keyword">const</span> username = <span class="hljs-keyword">await</span> harperGetUsername(accessToken)
      <span class="hljs-keyword">if</span> (username) {
        setUsername(username)
      }
    }
  })

  <span class="hljs-keyword">return</span> { username, setUsername }
}
</code></pre>
<p>Now we need to create the <code>harperGetUsername</code> function. This function will send the access token to HarperDB. HarperDB will then check if the access token is valid, and check which user it belongs to. If all is good, then HarperDB will send back the corresponding user's info.</p>
<pre><code class="lang-ts"><span class="hljs-comment">// src/utils/harperdb/getUsername.ts</span>

<span class="hljs-keyword">import</span> { DB_URL } <span class="hljs-keyword">from</span> <span class="hljs-string">"../../constants/constants"</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> harperGetUsername = <span class="hljs-keyword">async</span> (accessToken: <span class="hljs-built_in">string</span>) =&gt; {
  <span class="hljs-keyword">const</span> myHeaders = <span class="hljs-keyword">new</span> Headers()
  myHeaders.append(<span class="hljs-string">"Content-Type"</span>, <span class="hljs-string">"application/json"</span>)
  myHeaders.append(<span class="hljs-string">"Authorization"</span>, <span class="hljs-string">"Bearer "</span> + accessToken)

  <span class="hljs-keyword">const</span> raw = <span class="hljs-built_in">JSON</span>.stringify({
    operation: <span class="hljs-string">"user_info"</span>,
  })

  <span class="hljs-keyword">const</span> requestOptions: RequestInit = {
    method: <span class="hljs-string">"POST"</span>,
    headers: myHeaders,
    body: raw,
    redirect: <span class="hljs-string">"follow"</span>,
  }

  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(DB_URL, requestOptions)
    <span class="hljs-keyword">const</span> result = <span class="hljs-keyword">await</span> response.json()
    <span class="hljs-keyword">if</span> (response.status === <span class="hljs-number">200</span>) {
      <span class="hljs-keyword">return</span> result.username
    }
  } <span class="hljs-keyword">catch</span> (err) {
    <span class="hljs-built_in">console</span>.log(err)
  }
  <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>
}
</code></pre>
<p>Our <code>useUser</code> hook is made. Let's instantiate it in <code>_app.tsx</code> so that every time a new page is visited, the <code>useEffect</code> function will run and authenticate the user:</p>
<pre><code class="lang-tsx">// src/pages/_app.tsx

// ...
import { useUser } from "../custom-hooks/useUser"

function MyApp({ Component, pageProps }: AppProps) {
  // Remove below line
  // const [username, setUsername] = useState('');
  const { username, setUsername } = useUser()

  return (
    &lt;UserContext.Provider value={{ username, setUsername }}&gt;
      &lt;Layout&gt;
        &lt;Component {...pageProps} /&gt;
      &lt;/Layout&gt;
    &lt;/UserContext.Provider&gt;
  )
}

export default MyApp
</code></pre>
<p>Now when we refresh the page, the user's username is fetched using the access JWT stored in localStorage, keeping our user logged in. Awesome!</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/logged_in-1.JPG" alt="Image" width="600" height="400" loading="lazy">
<em>Logged in alert</em></p>
<h2 id="heading-how-to-log-out-the-user">How to Log Out the User</h2>
<p>The auth system we are implementing is "stateless" – meaning that no information will be stored in the database or on the server that tells us who is logged in and who isn't. Just an access JWT is stored on the client to authenticate users.</p>
<p>The only way we have of logging out a user is by deleting the access token in the user’s localStorage. Of course, if they are logged in on multiple devices, then they can only log out of the device they are on.</p>
<p>Also, if the access token was stolen, then anybody could pretend to be that user and access their data. This is a major weakness in our auth system. </p>
<p>One way to solve this would be to use <a target="_blank" href="https://auth0.com/blog/refresh-tokens-what-are-they-and-when-to-use-them/">refresh tokens</a>, but we'll keep things simple in this tutorial and just use one JWT for accessing protected routes.</p>
<p>In our <code>Navbar</code> components, let's add a logout button. We will use a ternary operator to display the "Login" and "Signup" links if <code>username</code> isn't set. If <code>username</code> is set, then the user is logged in so we can show them links to the "Timer" and "Stats" pages, as well as the "Logout" button.</p>
<pre><code class="lang-tsx">// src/components/layout/Navbar.tsx

import Link from "next/link"
import { useContext } from "react"
import { SITE_TITLE } from "../../constants/constants"
import { UserContext } from "../../contexts/UserContext"

const Navbar = () =&gt; {
  const { username, setUsername } = useContext(UserContext)

  const handleLogout = () =&gt; {
    localStorage.removeItem("access_token")
    setUsername("")
  }

  return (
    &lt;header className="flex justify-between items-center bg-green-600 text-white py-4 px-4"&gt;
      &lt;h2 className="text-lg"&gt;
        &lt;Link href="/"&gt;
          &lt;a&gt;{SITE_TITLE}&lt;/a&gt;
        &lt;/Link&gt;
      &lt;/h2&gt;
      &lt;nav&gt;
        &lt;ul className="flex items-center"&gt;
          {username ? (
            &lt;&gt;
              &lt;NavLink href="/"&gt;Timer&lt;/NavLink&gt;
              &lt;NavLink href="/stats"&gt;Stats&lt;/NavLink&gt;
              &lt;button
                onClick={handleLogout}
                className="border py-1 px-3 ml-8 rounded hover:bg-green-700"
                type="button"
              &gt;
                Logout
              &lt;/button&gt;
            &lt;/&gt;
          ) : (
            &lt;&gt;
              &lt;NavLink href="/login"&gt;Login&lt;/NavLink&gt;
              &lt;NavLink href="/signup"&gt;Signup&lt;/NavLink&gt;
            &lt;/&gt;
          )}
        &lt;/ul&gt;
      &lt;/nav&gt;
    &lt;/header&gt;
  )
}
// ...
</code></pre>
<h2 id="heading-the-login-page">The Login page</h2>
<p><a target="_blank" href="https://next-js-harper-db-task-timer.vercel.app/login">Here is the login page</a> we'll be building in this section.</p>
<h3 id="heading-login-page-ui">Login page UI</h3>
<p>Let's make the UI for the login page. First:</p>
<pre><code class="lang-tsx">// src/pages/login.tsx

import { useContext } from "react"
import type { NextPage } from "next"
import { UserContext } from "../contexts/UserContext"
import PageHeading from "../components/PageHeading"
import LoginForm from "../components/login-page/LoginForm"

const Login: NextPage = () =&gt; {
  const { username } = useContext(UserContext)

  return (
    &lt;div className="grow flex flex-col items-center mt-20"&gt;
      {username ? (
        &lt;p&gt;
          You are logged in as{" "}
          &lt;span className="text-green-600 font-semibold"&gt;{username}&lt;/span&gt; 👋
        &lt;/p&gt;
      ) : (
        &lt;&gt;
          &lt;PageHeading extraClasses="text-center mb-8"&gt;Log in&lt;/PageHeading&gt;
          &lt;LoginForm /&gt;
        &lt;/&gt;
      )}
    &lt;/div&gt;
  )
}

export default Login
</code></pre>
<p>Next, create <code>LoginForm</code>:</p>
<pre><code class="lang-tsx">// src/components/login-page/LoginForm.tsx

import { useState } from "react"
import { LabelAndInput } from "../Form"
import Button from "../Button"
import Alert from "../Alert"

const LoginForm = () =&gt; {
  const [username, setUsername] = useState("")
  const [password, setPassword] = useState("")

  return (
    &lt;form className="w-full sm:w-96"&gt;
      &lt;LabelAndInput
        label="Username"
        inputType="text"
        inputName="username"
        handleChange={e =&gt; setUsername(e.target.value)}
        value={username}
      /&gt;
      &lt;LabelAndInput
        label="Password"
        inputType="password"
        inputName="password"
        handleChange={e =&gt; setPassword(e.target.value)}
        value={password}
      /&gt;
      &lt;Button color="success" extraClasses="w-full mt-3 py-3 font-semibold"&gt;
        Login
      &lt;/Button&gt;

      {error &amp;&amp; &lt;Alert type="danger"&gt;{error}&lt;/Alert&gt;}
    &lt;/form&gt;
  )
}

export default LoginForm
</code></pre>
<p>Now we can create a <code>handleSubmit</code> function on our login form:</p>
<pre><code class="lang-tsx">// src/components/login-page/LoginForm.tsx

import { useState, useContext } from "react"
// ...
import { UserContext } from "../../contexts/UserContext"

const LoginForm = () =&gt; {
  // ...
  const [error, setError] = useState("")
  const user = useContext(UserContext)

  const handleSubmit = (e: React.FormEvent) =&gt; {
    e.preventDefault()
    setError("")
  }

  return (
    &lt;form className="w-full sm:w-96" onSubmit={handleSubmit}&gt;
      {/* ... */}
    &lt;/form&gt;
  )
}

export default LoginForm
</code></pre>
<p>Completing the rest of our <code>handleSubmit</code> function:</p>
<pre><code class="lang-tsx">// src/components/login-page/LoginForm.tsx

const handleSubmit = async (e: React.FormEvent) =&gt; {
  e.preventDefault()
  setError("")
  if (!username || !password) {
    setError("Username and password required")
    return
  }

  try {
    const { response, result } = await harperFetchJWTTokens(username, password)
    const { status } = response
    const accessToken = result.operation_token
    if (status === 200 &amp;&amp; accessToken) {
      authenticateUser(username, accessToken)
    } else if (status === 401) {
      setError("Check your username and password are correct")
    } else {
      setError("Whoops, something went wrong :(")
    }
  } catch (err) {
    console.log(err)
    setError("Whoops, something went wrong :(")
  }
}

const authenticateUser = (username: string, accessToken: string) =&gt; {
  user.setUsername(username)
  localStorage.setItem("access_token", accessToken)
}
</code></pre>
<p>Now if we enter the details of a user not in our database, we get an error:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/login_error.JPG" alt="login error" width="600" height="400" loading="lazy"></p>
<p>If we log in as a user that exists:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/login_success.JPG" alt="Log in successful" width="600" height="400" loading="lazy"></p>
<p>We can now create an account and log in to our app. Awesome!</p>
<h2 id="heading-create-a-tasks-context">Create a Tasks Context</h2>
<p>Our timer page ('/') and our stats page ('/stats') will both need to know the tasks that the user has added, as well as the number of seconds the user has spent on each task. We can share the tasks state between pages using the context API.</p>
<p>First, let's create a type for tasks so that TypeScript can tell us if a task is missing a property, or if we try to access a property that doesn't exist on tasks, making our code more robust:</p>
<pre><code class="lang-ts"><span class="hljs-comment">// src/types/Task.ts</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">interface</span> Task {
  __createdtime__: <span class="hljs-built_in">number</span>
  __updatedtime__: <span class="hljs-built_in">number</span>
  username: <span class="hljs-built_in">string</span>
  time_in_seconds: <span class="hljs-built_in">number</span>
  id: <span class="hljs-built_in">string</span>
  task_name: <span class="hljs-built_in">string</span>
}
</code></pre>
<p>Next, we can create our tasks context:</p>
<pre><code class="lang-tsx">// src/contexts/TasksContext.ts

import React, { createContext } from "react"
import type { Task } from "../types/Task"

interface TasksContext {
  tasks: Task[]
  setTasks: React.Dispatch&lt;React.SetStateAction&lt;Task[]&gt;&gt;
  getAndSetTasks: (username: string) =&gt; Promise&lt;void&gt;
}

export const TasksContext = createContext({} as TasksContext)
</code></pre>
<p>Before we wrap our application with the tasks context provider, let's create a custom hook that will contain a <code>useEffect</code> hook that will run every time a new page is visited, or every time a page is refreshed. It will check if the user is logged in, and if the tasks state contains no tasks, it will try to fetch tasks from the database:</p>
<pre><code class="lang-tsx">// src/custom-hooks/useTasks.ts

import { useState, useCallback, useEffect } from "react"
import type { Task } from "../types/Task"
import { harperGetTasks } from "../utils/harperdb/getTasks"

export const useTasks = (username: string) =&gt; {
  const [tasks, setTasks] = useState&lt;Task[]&gt;([])

  // Get tasks from db then set task state
  const getAndSetTasks = useCallback(
    async (username: string) =&gt; {
      try {
        const tasks: Task[] = await harperGetTasks(username)
        setTasks(tasks)
      } catch (err) {
        console.log(err)
      }
    },
    [setTasks]
  )

  useEffect(() =&gt; {
    if (!username || tasks.length &gt; 0) return
    getAndSetTasks(username)
  }, [username, tasks.length, getAndSetTasks])

  return { tasks, setTasks, getAndSetTasks }
}
</code></pre>
<p>Now we need to define the <code>harperGetTasks</code> function to fetch all tasks from the database that have our user's username. As you can see, HarperDB supports both SQL and NoSQL operations. We are ordering the tasks with the ones the user most recently worked on at the top:</p>
<pre><code class="lang-ts"><span class="hljs-comment">// src/utils/harperdb/getTasks.ts</span>

<span class="hljs-keyword">import</span> { harperFetch } <span class="hljs-keyword">from</span> <span class="hljs-string">"./harperFetch"</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> harperGetTasks = <span class="hljs-keyword">async</span> (username: <span class="hljs-built_in">string</span>) =&gt; {
  <span class="hljs-keyword">const</span> data = {
    operation: <span class="hljs-string">"sql"</span>,
    sql: <span class="hljs-string">`SELECT * FROM productivity_timer.tasks WHERE username = '<span class="hljs-subst">${username}</span>' ORDER BY __updatedtime__ DESC`</span>,
  }

  <span class="hljs-keyword">const</span> { result } = <span class="hljs-keyword">await</span> harperFetch(data)
  <span class="hljs-keyword">return</span> result
}
</code></pre>
<p>All of our HarperDB functions from now on include the same boilerplate, so I created a <code>harperFetch</code> utility function to keep the code DRY:</p>
<pre><code class="lang-ts"><span class="hljs-comment">// src/utils/harperFetch.ts</span>

<span class="hljs-keyword">import</span> { DB_URL } <span class="hljs-keyword">from</span> <span class="hljs-string">"../../constants/constants"</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> harperFetch = <span class="hljs-keyword">async</span> (data: { [key: <span class="hljs-built_in">string</span>]: <span class="hljs-built_in">any</span> }) =&gt; {
  <span class="hljs-keyword">const</span> accessToken = <span class="hljs-built_in">localStorage</span>.getItem(<span class="hljs-string">"access_token"</span>)
  <span class="hljs-keyword">if</span> (!accessToken) <span class="hljs-keyword">throw</span> { error: <span class="hljs-string">"You need to log in"</span> }

  <span class="hljs-keyword">const</span> myHeaders = <span class="hljs-keyword">new</span> Headers()
  myHeaders.append(<span class="hljs-string">"Content-Type"</span>, <span class="hljs-string">"application/json"</span>)
  myHeaders.append(<span class="hljs-string">"Authorization"</span>, <span class="hljs-string">"Bearer "</span> + accessToken)

  <span class="hljs-keyword">const</span> raw = <span class="hljs-built_in">JSON</span>.stringify(data)

  <span class="hljs-keyword">const</span> requestOptions: RequestInit = {
    method: <span class="hljs-string">"POST"</span>,
    headers: myHeaders,
    body: raw,
    redirect: <span class="hljs-string">"follow"</span>,
  }

  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(DB_URL, requestOptions)
  <span class="hljs-keyword">const</span> result = <span class="hljs-keyword">await</span> response.json()
  <span class="hljs-keyword">return</span> { response, result }
}
</code></pre>
<p>OK, let's now give all pages in our application access to the <code>tasks</code> state:</p>
<pre><code class="lang-tsx">// src/pages/_app.tsx

// ...
import { TasksContext } from "../contexts/TasksContext"
import { useTasks } from "../custom-hooks/useTasks"

function MyApp({ Component, pageProps }: AppProps) {
  // ...
  const { tasks, setTasks, getAndSetTasks } = useTasks(username)

  console.log(tasks)

  return (
    &lt;UserContext.Provider value={{ username, setUsername }}&gt;
      &lt;TasksContext.Provider value={{ tasks, setTasks, getAndSetTasks }}&gt;
        &lt;Layout&gt;
          &lt;Component {...pageProps} /&gt;
        &lt;/Layout&gt;
      &lt;/TasksContext.Provider&gt;
    &lt;/UserContext.Provider&gt;
  )
}

export default MyApp
</code></pre>
<p>Now, I am logged in as "dan", so I should now see all of dan's tasks console.logged – and I do:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/dans_tasks.JPG" alt="dan's tasks" width="600" height="400" loading="lazy"></p>
<h2 id="heading-create-the-task-timer-page">Create the Task Timer Page</h2>
<p>The homepage UI needs to look like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/home_page.JPG" alt="home page" width="600" height="400" loading="lazy"></p>
<p>The top row is where the user can select one of their tasks stored in the database from a dropdown menu. They can also add a new task to the database.</p>
<p>Then below, we have the timer that will track how long the user has spent on each task.</p>
<p><a target="_blank" href="https://next-js-harper-db-task-timer.vercel.app/">Here is the page we'll be building</a> in this section.</p>
<h2 id="heading-create-the-addselect-taskbar">Create the Add/Select Taskbar</h2>
<p>Let's first create the select or add a task row, making it as a component to be imported into the home page:</p>
<pre><code class="lang-tsx">// src/components/home-page/Taskbar.tsx

import { useState, useContext } from "react"
import { harperAddNewTask } from "../../utils/harperdb/addNewTask"
import { UserContext } from "../../contexts/UserContext"
import { TasksContext } from "../../contexts/TasksContext"
import Button from "../Button"

interface Props {
  selectedTaskId: string
  setSelectedTaskId: React.Dispatch&lt;React.SetStateAction&lt;string&gt;&gt;
  setErrorMessage: React.Dispatch&lt;React.SetStateAction&lt;string&gt;&gt;
  setSeconds: React.Dispatch&lt;React.SetStateAction&lt;number&gt;&gt;
  pauseTimer: () =&gt; void
}

const TaskBar = ({
  selectedTaskId,
  setSelectedTaskId,
  setErrorMessage,
  setSeconds,
  pauseTimer,
}: Props) =&gt; {
  const { username } = useContext(UserContext)
  const { tasks, getAndSetTasks } = useContext(TasksContext)

  const [isUserAddingNewTask, setIsUserAddingNewTask] = useState(false)
  const [taskInputValue, setTaskInputValue] = useState("")

  const handleChangeTaskInput = (e: { target: HTMLInputElement }) =&gt; {
    setTaskInputValue(e.target.value)
  }

  const handleSelectTask = (e: { target: HTMLSelectElement }) =&gt; {
    setErrorMessage("")
    setSelectedTaskId(e.target.value)
    setSeconds(0)
    pauseTimer()
  }

  const handleClickAddNewTask = () =&gt; {
    if (taskInputValue.trim() === "") {
      setErrorMessage("Type a task!")
      return
    }
    addNewTask()
    resetAddingNewTask()
  }

  const addNewTask = async () =&gt; {
    try {
      const { response } = await harperAddNewTask(username, taskInputValue)
      if (response.status === 200) {
        // Task added to db successfully
        getAndSetTasks(username)
      } else setErrorMessage("Whoops, something went wrong")
    } catch (err) {
      console.log(err)
      setErrorMessage("Whoops, something went wrong")
    }
  }

  const resetAddingNewTask = () =&gt; {
    setTaskInputValue("")
    setIsUserAddingNewTask(false)
  }

  return (
    &lt;div&gt;
      {isUserAddingNewTask ? (
        &lt;&gt;
          &lt;input
            type="text"
            placeholder="Enter task here..."
            value={taskInputValue}
            onChange={handleChangeTaskInput}
            className="border p-2 mr-2"
          /&gt;
          &lt;Button color="primary" handleClick={handleClickAddNewTask}&gt;
            Add task
          &lt;/Button&gt;
          &lt;Button
            color="secondary"
            handleClick={() =&gt; setIsUserAddingNewTask(false)}
            extraClasses="ml-1"
          &gt;
            Cancel
          &lt;/Button&gt;
        &lt;/&gt;
      ) : (
        &lt;&gt;
          &lt;select
            className="mr-4 p-2 border"
            name="task"
            id="task"
            onChange={handleSelectTask}
          &gt;
            {selectedTaskId === "" &amp;&amp; (
              &lt;option disabled selected value="" hidden&gt;
                -- Select a task --
              &lt;/option&gt;
            )}
            {tasks.map(task =&gt; (
              &lt;option
                key={task.id}
                value={task.id}
                selected={task.id === selectedTaskId}
              &gt;
                {task.task_name}
              &lt;/option&gt;
            ))}
          &lt;/select&gt;
          &lt;Button
            handleClick={() =&gt; setIsUserAddingNewTask(true)}
            color="primary"
          &gt;
            New Task
          &lt;/Button&gt;
        &lt;/&gt;
      )}
    &lt;/div&gt;
  )
}

export default TaskBar
</code></pre>
<p>Above, in the JSX, when the user clicks the "New Task" button, <code>isUserAddingNewTask</code> is set to true, and the first part of the ternary statement is rendered. This allows the user to add a new task.</p>
<p>Let's create the <code>harperAddNewTask</code> function:</p>
<pre><code class="lang-ts"><span class="hljs-comment">// src/utils/harperdb/addNewTask.ts</span>

<span class="hljs-keyword">import</span> { harperFetch } <span class="hljs-keyword">from</span> <span class="hljs-string">"./harperFetch"</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> harperAddNewTask = <span class="hljs-keyword">async</span> (username: <span class="hljs-built_in">string</span>, taskName: <span class="hljs-built_in">string</span>) =&gt; {
  <span class="hljs-keyword">const</span> data = {
    operation: <span class="hljs-string">"insert"</span>,
    schema: <span class="hljs-string">"productivity_timer"</span>,
    table: <span class="hljs-string">"tasks"</span>,
    records: [
      {
        username: username,
        task_name: taskName,
        time_in_seconds: <span class="hljs-number">0</span>,
      },
    ],
  }

  <span class="hljs-keyword">const</span> responseAndResult = <span class="hljs-keyword">await</span> harperFetch(data)
  <span class="hljs-keyword">return</span> responseAndResult
}
</code></pre>
<p>Now, if we import our <code>Taskbar</code> into the home page, we will see it:</p>
<pre><code class="lang-tsx">// src/pages/index.tsx

import type { NextPage } from "next"
import Taskbar from "../components/home-page/Taskbar"

const Home: NextPage = () =&gt; {
  return (
    &lt;div&gt;
      &lt;Taskbar /&gt;
    &lt;/div&gt;
  )
}

export default Home
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/taskbar.JPG" alt="task bar" width="600" height="400" loading="lazy"></p>
<p>TypeScript is correctly telling us off because <code>Taskbar</code> is missing some props, but we will come back to that soon.</p>
<h3 id="heading-create-the-timer">Create the timer</h3>
<p>First, let's write a function that will take a task ID and time in seconds, and update the task in the database:</p>
<pre><code class="lang-ts"><span class="hljs-comment">// src/utils/harperdb/saveTaskTime.ts</span>

<span class="hljs-keyword">import</span> { harperFetch } <span class="hljs-keyword">from</span> <span class="hljs-string">"./harperFetch"</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> harperSaveTaskTime = <span class="hljs-keyword">async</span> (
  taskId: <span class="hljs-built_in">string</span>,
  newSeconds: <span class="hljs-built_in">number</span>
) =&gt; {
  <span class="hljs-keyword">const</span> data = {
    operation: <span class="hljs-string">"sql"</span>,
    sql: <span class="hljs-string">`UPDATE productivity_timer.tasks SET time_in_seconds = '<span class="hljs-subst">${newSeconds}</span>' WHERE id = '<span class="hljs-subst">${taskId}</span>'`</span>,
  }

  <span class="hljs-keyword">const</span> responseAndResult = <span class="hljs-keyword">await</span> harperFetch(data)
  <span class="hljs-keyword">return</span> responseAndResult
}
</code></pre>
<p>Next, create a custom hook to keep the state of the seconds (<code>seconds</code>), whether the timer is running (<code>isTimerOn</code>), and the functions needed to start and stop the timer from running:</p>
<pre><code class="lang-ts"><span class="hljs-comment">// src/custom-hooks/useTimer.ts</span>

<span class="hljs-keyword">import</span> { useState, useRef } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>

<span class="hljs-keyword">const</span> useTimer = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> [isTimerOn, setIsTimerOn] = useState(<span class="hljs-literal">false</span>)
  <span class="hljs-keyword">const</span> [seconds, setSeconds] = useState(<span class="hljs-number">0</span>)

  <span class="hljs-keyword">const</span> intervalRef = useRef&lt;NodeJS.Timer | <span class="hljs-literal">null</span>&gt;(<span class="hljs-literal">null</span>)

  <span class="hljs-keyword">const</span> startTimer = <span class="hljs-function">() =&gt;</span> {
    setIsTimerOn(<span class="hljs-literal">true</span>)

    <span class="hljs-keyword">const</span> intervalId = <span class="hljs-built_in">setInterval</span>(<span class="hljs-function">() =&gt;</span> {
      setSeconds(<span class="hljs-function"><span class="hljs-params">prev</span> =&gt;</span> prev + <span class="hljs-number">1</span>)
    }, <span class="hljs-number">1000</span>)

    intervalRef.current = intervalId
  }

  <span class="hljs-keyword">const</span> pauseTimer = <span class="hljs-function">() =&gt;</span> {
    setIsTimerOn(<span class="hljs-literal">false</span>)
    <span class="hljs-built_in">clearInterval</span>(intervalRef.current <span class="hljs-keyword">as</span> NodeJS.Timeout)
  }

  <span class="hljs-keyword">return</span> {
    isTimerOn,
    seconds,
    setSeconds,
    startTimer,
    pauseTimer,
  }
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> useTimer
</code></pre>
<p>On our timer, we want to display the time in hours:mins:seconds, but we will be recording the time passed in seconds. So we need a way of converting seconds into HH:MM:SS. We will do this with a <code>formatTime</code> utility function:</p>
<pre><code class="lang-ts"><span class="hljs-comment">// src/utils/formatTime.ts</span>

<span class="hljs-keyword">const</span> SECONDS_PER_HOUR = <span class="hljs-number">3600</span>
<span class="hljs-keyword">const</span> SECONDS_PER_MINUTE = <span class="hljs-number">60</span>

<span class="hljs-comment">// HH:MM:SS</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> formatTime = <span class="hljs-function">(<span class="hljs-params">seconds: <span class="hljs-built_in">number</span></span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> { hours, mins, secs } = calculateHoursMinsAndSecs(seconds)

  <span class="hljs-keyword">const</span> formattedHours = prependZeroIfLessThanTen(hours)
  <span class="hljs-keyword">const</span> formattedMins = prependZeroIfLessThanTen(mins)
  <span class="hljs-keyword">const</span> formattedSecs = prependZeroIfLessThanTen(secs)

  <span class="hljs-keyword">return</span> {
    formattedHours,
    formattedMins,
    formattedSecs,
  }
}

<span class="hljs-comment">// Prefix time with 0 if less than 10. E.g. '1' =&gt; '01'.</span>
<span class="hljs-keyword">const</span> prependZeroIfLessThanTen = <span class="hljs-function">(<span class="hljs-params">time: <span class="hljs-built_in">number</span></span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> formattedTime: <span class="hljs-built_in">string</span> = time &lt; <span class="hljs-number">10</span> ? <span class="hljs-string">`0<span class="hljs-subst">${time}</span>`</span> : <span class="hljs-string">`<span class="hljs-subst">${time}</span>`</span>
  <span class="hljs-keyword">return</span> formattedTime
}

<span class="hljs-comment">// Convert seconds into hours, mins, and secs</span>
<span class="hljs-keyword">const</span> calculateHoursMinsAndSecs = <span class="hljs-function">(<span class="hljs-params">seconds: <span class="hljs-built_in">number</span></span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> hours = calculateHours(seconds)
  <span class="hljs-keyword">const</span> mins = calculateMins(seconds)
  <span class="hljs-keyword">const</span> secs = calculateSecs(seconds)

  <span class="hljs-keyword">return</span> {
    hours,
    mins,
    secs,
  }
}

<span class="hljs-keyword">const</span> calculateHours = <span class="hljs-function">(<span class="hljs-params">seconds: <span class="hljs-built_in">number</span></span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> hours = <span class="hljs-built_in">Math</span>.floor(seconds / SECONDS_PER_HOUR)
  <span class="hljs-keyword">return</span> hours
}

<span class="hljs-keyword">const</span> calculateMins = <span class="hljs-function">(<span class="hljs-params">seconds: <span class="hljs-built_in">number</span></span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> mins = <span class="hljs-built_in">Math</span>.floor((seconds % SECONDS_PER_HOUR) / SECONDS_PER_MINUTE)
  <span class="hljs-keyword">return</span> mins
}

<span class="hljs-keyword">const</span> calculateSecs = <span class="hljs-function">(<span class="hljs-params">seconds: <span class="hljs-built_in">number</span></span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> secs = <span class="hljs-built_in">Math</span>.floor((seconds % SECONDS_PER_HOUR) % SECONDS_PER_MINUTE)
  <span class="hljs-keyword">return</span> secs
}
</code></pre>
<p>Let's now create our Timer component (note: don't panic, we will pass all of the props down next!):</p>
<pre><code class="lang-tsx">// src/components/home-page/Timer.tsx

import { useContext } from "react"
import { TasksContext } from "../../contexts/TasksContext"
import { UserContext } from "../../contexts/UserContext"
import { formatTime } from "../../utils/formatTime"
import { harperSaveTaskTime } from "../../utils/harperdb/saveTaskTime"
import Button from "../Button"
import type { RecentTaskTime } from "../../types/RecentTaskTime"

interface TimerProps {
  seconds: number
  setSeconds: React.Dispatch&lt;React.SetStateAction&lt;number&gt;&gt;
  isTimerOn: boolean
  startTimer: () =&gt; void
  pauseTimer: () =&gt; void
  setErrorMessage: React.Dispatch&lt;React.SetStateAction&lt;string&gt;&gt;
  selectedTaskId: string
  selectedTaskName: string
  setRecentTaskTimes: React.Dispatch&lt;React.SetStateAction&lt;RecentTaskTime[]&gt;&gt;
}

export const Timer: React.FC&lt;TimerProps&gt; = ({
  seconds,
  setSeconds,
  isTimerOn,
  startTimer,
  pauseTimer,
  setErrorMessage,
  selectedTaskId,
  selectedTaskName,
  setRecentTaskTimes,
}) =&gt; {
  const { tasks, getAndSetTasks } = useContext(TasksContext)
  const { username } = useContext(UserContext)

  const { formattedHours, formattedMins, formattedSecs } = formatTime(seconds)

  const handleStartTimer = () =&gt; {
    setErrorMessage("")
    if (selectedTaskId == "") {
      setErrorMessage("Please select a task")
    } else {
      startTimer()
    }
  }

  const handleLogTime = async () =&gt; {
    pauseTimer()
    const prevTaskSeconds = getTaskTimeFromId(selectedTaskId)
    const newTaskSeconds = prevTaskSeconds + seconds
    const { response, result } = await harperSaveTaskTime(
      selectedTaskId,
      newTaskSeconds
    )
    if (response.status === 200) {
      getAndSetTasks(username)
      setSeconds(0)
      setRecentTaskTimes(prev =&gt; [
        { name: selectedTaskName, seconds: seconds },
        ...prev,
      ])
    } else setErrorMessage("Whoops, something went wrong :(")
    console.log({ response, result })
  }

  const getTaskTimeFromId = (id: string) =&gt; {
    const task = tasks.find(task =&gt; task.id === id)
    if (!task) return 0
    return task.time_in_seconds
  }

  const handleResetTimer = () =&gt; {
    pauseTimer()
    setSeconds(0)
  }

  return (
    &lt;div&gt;
      &lt;div className="mt-8 border-2 border-gray-500 rounded p-14 text-5xl"&gt;
        {formattedHours} : {formattedMins} : {formattedSecs}
      &lt;/div&gt;
      &lt;div className="flex justify-center mt-10"&gt;
        {/* Pause and start the timer buttons */}
        {isTimerOn ? (
          &lt;&gt;
            &lt;Button color="warning" handleClick={pauseTimer}&gt;
              Pause
            &lt;/Button&gt;
          &lt;/&gt;
        ) : (
          &lt;Button color="success" handleClick={handleStartTimer}&gt;
            Start
          &lt;/Button&gt;
        )}

        {/* Button to update the time in the db for the chosen task */}
        {(seconds &gt; 0 || isTimerOn) &amp;&amp; (
          &lt;Button
            color="danger"
            handleClick={handleLogTime}
            extraClasses="ml-4"
          &gt;
            Log time
          &lt;/Button&gt;
        )}
      &lt;/div&gt;

      {/* Stop timer and reset to 0 secs */}
      {(seconds &gt; 0 || isTimerOn) &amp;&amp; (
        &lt;button
          onClick={handleResetTimer}
          className="underline underline-offset-2 mt-8 cursor-pointer text-gray-500 mx-auto block"
        &gt;
          Reset
        &lt;/button&gt;
      )}
    &lt;/div&gt;
  )
}

interface TimerBtnProps {
  handleClick: () =&gt; void
  text: string
  extraClasses?: string
}

export const TimerBtn: React.FC&lt;TimerBtnProps&gt; = ({
  handleClick,
  text,
  extraClasses,
}) =&gt; {
  return (
    &lt;button
      className={`${
        text === "Start" ? "bg-blue-500" : "bg-red-500"
      } rounded px-4 py-2 text-white mt-8 ${extraClasses}`}
      onClick={handleClick}
    &gt;
      {text}
    &lt;/button&gt;
  )
}
</code></pre>
<p>We can now add <code>Taskbar</code> and <code>Timer</code> to our index page, and pass down all necessary props to these components:</p>
<pre><code class="lang-tsx">// src/pages/index.tsx

import { useState, useContext } from "react"
import type { NextPage } from "next"
import type { RecentTaskTime } from "../types/RecentTaskTime"
import { UserContext } from "../contexts/UserContext"
import useTimer from "../custom-hooks/useTimer"
import Taskbar from "../components/home-page/Taskbar"
import { Timer } from "../components/home-page/Timer"
import Alert from "../components/Alert"
import Link from "../components/Link"

const Home: NextPage = () =&gt; {
  const [selectedTaskId, setSelectedTaskId] = useState("")
  const [selectedTaskName, setSelectedTaskName] = useState("")
  const [errorMessage, setErrorMessage] = useState("")
  const [recentTaskTimes, setRecentTaskTimes] = useState&lt;RecentTaskTime[]&gt;([])

  const { isTimerOn, seconds, setSeconds, startTimer, pauseTimer } = useTimer()

  const { username } = useContext(UserContext)

  return (
    &lt;div className="flex flex-col items-center justify-center pt-4 grow"&gt;
      {!username &amp;&amp; (
        &lt;Alert type="warning" extraClasses="mb-12"&gt;
          Please &lt;Link href="/login"&gt;log in&lt;/Link&gt; or{" "}
          &lt;Link href="/signup"&gt;create an account&lt;/Link&gt; to use Super
          Productivity Timer
        &lt;/Alert&gt;
      )}

      &lt;Taskbar
        selectedTaskId={selectedTaskId}
        setSelectedTaskId={setSelectedTaskId}
        setSelectedTaskName={setSelectedTaskName}
        setErrorMessage={setErrorMessage}
        setSeconds={setSeconds}
        pauseTimer={pauseTimer}
      /&gt;
      &lt;Timer
        seconds={seconds}
        setSeconds={setSeconds}
        setRecentTaskTimes={setRecentTaskTimes}
        selectedTaskName={selectedTaskName}
        isTimerOn={isTimerOn}
        startTimer={startTimer}
        pauseTimer={pauseTimer}
        setErrorMessage={setErrorMessage}
        selectedTaskId={selectedTaskId}
      /&gt;

      {errorMessage &amp;&amp; &lt;div className="text-red-500 mt-4"&gt;{errorMessage}&lt;/div&gt;}
    &lt;/div&gt;
  )
}

export default Home
</code></pre>
<p>Our timer should now be working. Try adding a task, starting the timer, then logging the time. It should show up in your HarperDB database:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/db_times.JPG" alt="db times" width="600" height="400" loading="lazy"></p>
<h3 id="heading-add-a-recently-completed-times-log">Add a recently completed times log</h3>
<p>Let's finish off our timer page by adding a log to give the user feedback that the times have been recorded successfully. It will look like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/log.JPG" alt="log of times" width="600" height="400" loading="lazy"></p>
<p>Create a type called <code>RecentTaskTime</code>:</p>
<pre><code class="lang-ts"><span class="hljs-comment">// src/types/RecentTaskTime.ts</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">interface</span> RecentTaskTime {
  name: <span class="hljs-built_in">string</span>
  seconds: <span class="hljs-built_in">number</span>
}
</code></pre>
<p>Then in <code>index.tsx</code>:</p>
<pre><code class="lang-tsx">// ...
import LogOfRecentTaskTimes from "../components/home-page/LogOfRecentTaskTimes"

const Home: NextPage = () =&gt; {
  // ...
  const [recentTaskTimes, setRecentTaskTimes] = useState&lt;RecentTaskTime[]&gt;([])

  return (
    &lt;div className="flex flex-col items-center justify-center pt-4 grow"&gt;
      {/* ... */}

      {recentTaskTimes.length &gt; 0 &amp;&amp; (
        &lt;LogOfRecentTaskTimes recentTaskTimes={recentTaskTimes} /&gt;
      )}
    &lt;/div&gt;
  )
}
</code></pre>
<p>Now let's create the <code>LogOfRecentTaskTimes</code> component:</p>
<pre><code class="lang-tsx">// src/components/home-page/LogOfRecentTaskTimes.tsx

import type { RecentTaskTime } from "../../types/RecentTaskTime"

interface Props {
  recentTaskTimes: RecentTaskTime[]
}

const LogOfRecentTaskTimes = ({ recentTaskTimes }: Props) =&gt; {
  return (
    &lt;div className="mt-8 max-h-56 overflow-y-auto px-8"&gt;
      {recentTaskTimes.map((t, i) =&gt; (
        &lt;div key={i} className="flex shadow rounded px-8 py-4 mt-2"&gt;
          &lt;p&gt;
            &lt;span className="text-green-600"&gt;{t.seconds}&lt;/span&gt; seconds added to{" "}
            &lt;span className="text-green-600"&gt;{t.name}&lt;/span&gt;
          &lt;/p&gt;
        &lt;/div&gt;
      ))}
    &lt;/div&gt;
  )
}

export default LogOfRecentTaskTimes
</code></pre>
<p>Our timer page is complete 🎉</p>
<h2 id="heading-the-stats-page">The Stats Page</h2>
<p>Well done if you made it this far! We only have one more page to go: <a target="_blank" href="https://next-js-harper-db-task-timer.vercel.app/stats">the stats page</a>.</p>
<p>In the stats page, we'll be fetching all of the user's tasks from the HarperDB tasks table, and displaying them nicely in a table.</p>
<p>First, we will need some utility functions to display time and date nicely in our stats page table. Add the following two functions to our formatTime utils file:</p>
<pre><code class="lang-ts"><span class="hljs-comment">// src/utils/formatTime.ts</span>

<span class="hljs-comment">// ...</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> displayTimeString = <span class="hljs-function">(<span class="hljs-params">seconds: <span class="hljs-built_in">number</span></span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> { formattedHours, formattedMins, formattedSecs } = formatTime(seconds)
  <span class="hljs-keyword">return</span> <span class="hljs-string">`<span class="hljs-subst">${formattedHours}</span>h <span class="hljs-subst">${formattedMins}</span>m <span class="hljs-subst">${formattedSecs}</span>s`</span>
}

<span class="hljs-comment">// timestamp =&gt; dd/mm/yyyy</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> timestampToDayMonthYear = <span class="hljs-function">(<span class="hljs-params">timestamp: <span class="hljs-built_in">number</span></span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> date = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(timestamp)
  <span class="hljs-keyword">const</span> formattedDate = date.toLocaleDateString()
  <span class="hljs-keyword">return</span> formattedDate
}

<span class="hljs-comment">// ...</span>
</code></pre>
<p>We can now create a table, and loop through <code>tasks</code> to display the data in the table rows. At the end of each row, I've added a delete button so the user can permanently delete tasks from the DB:</p>
<pre><code class="lang-tsx">// src/pages/stats.tsx

import { useState, useContext } from "react"
import type { NextPage } from "next"
import { UserContext } from "../contexts/UserContext"
import { TasksContext } from "../contexts/TasksContext"
import Header from "../components/PageHeading"
import Link from "../components/Link"
import Alert from "../components/Alert"
import { displayTimeString, timestampToDayMonthYear } from "../utils/formatTime"
import { harperDeleteTask } from "../utils/harperdb/deleteTask"

const Stats: NextPage = () =&gt; {
  const [errorMessage, setErrorMessage] = useState("")

  const { username } = useContext(UserContext)
  const { tasks, getAndSetTasks } = useContext(TasksContext)

  const handleDeleteRow = async (taskId: string) =&gt; {
    setErrorMessage("")
    const areYouSure = confirm("Are you sure you want to delete this row?")
    if (!areYouSure) return

    try {
      // Delete task from db
      const { response } = await harperDeleteTask(taskId)
      if (response.status === 200) {
        // Get tasks from db and setTasks
        getAndSetTasks(username)
        return
      }
    } catch (err) {
      console.log(err)
    }
    setErrorMessage("Whoops, something went wrong :(")
  }

  return (
    &lt;div&gt;
      {!username &amp;&amp; (
        &lt;Alert type="warning" extraClasses="mb-12"&gt;
          Please &lt;Link href="/login"&gt;log in&lt;/Link&gt; or{" "}
          &lt;Link href="/signup"&gt;create an account&lt;/Link&gt; to use Super
          Productivity Timer
        &lt;/Alert&gt;
      )}

      &lt;Header extraClasses="mb-6 text-center mt-8"&gt;Stats&lt;/Header&gt;

      {errorMessage &amp;&amp; (
        &lt;p className="text-center text-red-500 mb-8"&gt;{errorMessage}&lt;/p&gt;
      )}

      &lt;div className="overflow-x-auto "&gt;
        &lt;table className="table-auto border-collapse border border-slate-400 w-full sm:w-3/4 mx-auto"&gt;
          &lt;thead className="bg-slate-100 text-left"&gt;
            &lt;tr&gt;
              &lt;TH&gt;Task&lt;/TH&gt;
              &lt;TH&gt;Total Time&lt;/TH&gt;
              &lt;TH&gt;Last Updated&lt;/TH&gt;
              &lt;TH&gt;Start Date&lt;/TH&gt;
              &lt;TH&gt;Delete&lt;/TH&gt;
            &lt;/tr&gt;
          &lt;/thead&gt;
          &lt;tbody&gt;
            {tasks.length &gt; 0 &amp;&amp;
              tasks.map(task =&gt; (
                &lt;tr key={task.id}&gt;
                  &lt;TD&gt;{task.task_name}&lt;/TD&gt;
                  &lt;TD&gt;{displayTimeString(task.time_in_seconds)}&lt;/TD&gt;
                  &lt;TD&gt;{timestampToDayMonthYear(task.__updatedtime__)}&lt;/TD&gt;
                  &lt;TD&gt;{timestampToDayMonthYear(task.__createdtime__)}&lt;/TD&gt;
                  &lt;TD&gt;
                    &lt;button
                      onClick={() =&gt; handleDeleteRow(task.id)}
                      className="bg-red-500 text-white rounded px-3 py-1"
                    &gt;
                      x
                    &lt;/button&gt;
                  &lt;/TD&gt;
                &lt;/tr&gt;
              ))}
          &lt;/tbody&gt;
        &lt;/table&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  )
}

const TH: React.FC&lt;{ children: string }&gt; = ({ children }) =&gt; {
  const classes = "border border-slate-300 rounded-top p-4"
  return &lt;th className={classes}&gt;{children}&lt;/th&gt;
}

interface TDProps {
  children: React.ReactNode
}
const TD = ({ children }: TDProps) =&gt; {
  const classes = "border border-slate-300 p-4"
  return &lt;td className={classes}&gt;{children}&lt;/td&gt;
}

export default Stats
</code></pre>
<p>And here is our stats page:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/stats_table.JPG" alt="Stats table" width="600" height="400" loading="lazy"></p>
<p>One last thing to do: create the <code>harperDeleteTask</code> function:</p>
<pre><code class="lang-ts"><span class="hljs-comment">// src/utils/harperdb/deleteTask.ts</span>

<span class="hljs-keyword">import</span> { harperFetch } <span class="hljs-keyword">from</span> <span class="hljs-string">"./harperFetch"</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> harperDeleteTask = <span class="hljs-keyword">async</span> (taskId: <span class="hljs-built_in">string</span>) =&gt; {
  <span class="hljs-keyword">const</span> data = {
    operation: <span class="hljs-string">"delete"</span>,
    schema: <span class="hljs-string">"productivity_timer"</span>,
    table: <span class="hljs-string">"tasks"</span>,
    hash_values: [taskId],
  }

  <span class="hljs-keyword">const</span> responseAndResult = <span class="hljs-keyword">await</span> harperFetch(data)
  <span class="hljs-keyword">return</span> responseAndResult
}
</code></pre>
<p>Now try deleting a task and checking your DB – it will be gone. Perfect!</p>
<p>Also, try adding a new task, then logging some time. Then go to the stats page and you'll see that the stats page is updated, too.</p>
<p>You now know how to build a full stack application with NextJS and HarperDB.</p>
<h2 id="heading-thank-you-for-reading">Thank you for reading!</h2>
<p>If you found this article useful, feel free to:</p>
<ul>
<li><a target="_blank" href="https://www.youtube.com/channel/UC0URylW_U4i26wN231yRqvA">Subscribe to my YouTube channel</a>. I plan to turn it into a React/NextJS/Node-focused channel.</li>
<li><a target="_blank" href="https://twitter.com/doabledanny">Follow me on Twitter</a> where I tweet about my freelancing journey, side projects, and current learnings.</li>
</ul>
<p>Cheers!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Learn TypeScript – The Ultimate Beginners Guide ]]>
                </title>
                <description>
                    <![CDATA[ TypeScript has become increasingly popular over the last few years, and many jobs are now requiring developers to know TypeScript.  But don't be alarmed – if you already know JavaScript, you will be able to pick up TypeScript quickly.  Even if you do... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/learn-typescript-beginners-guide/</link>
                <guid isPermaLink="false">66c8c999e9e57963a5d82ad5</guid>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ TypeScript ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Danny ]]>
                </dc:creator>
                <pubDate>Thu, 27 Jan 2022 17:47:36 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/01/Cheat-Sheet-Poster--1-.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>TypeScript has become increasingly popular over the last few years, and many jobs are now requiring developers to know TypeScript. </p>
<p>But don't be alarmed – if you already know JavaScript, you will be able to pick up TypeScript quickly. </p>
<p>Even if you don't plan on using TypeScript, learning it will give you a better understanding of JavaScript – and make you a better developer.</p>
<p>In this article, you will learn:</p>
<ul>
<li>What is TypeScript and why should I learn it?</li>
<li>How to set up a project with TypeScript</li>
<li>All of the main TypeScript concepts (types, interfaces, generics, type-casting, and more...)</li>
<li>How to use TypeScript with React</li>
</ul>
<p>I also made a <a target="_blank" href="https://doabledanny.gumroad.com/l/typescript-cheat-sheet-pdf">TypeScript cheat sheet PDF</a> and <a target="_blank" href="https://doabledanny.gumroad.com/l/typescript-cheat-sheet-poster">poster</a> that summarizes this article down to one page. This makes it easy to look up and revise concepts/syntax quickly.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/01/TypeScript-Cheat-Sheet--DARK-.png" alt="TypeScript cheat sheet PDF" width="600" height="400" loading="lazy">
<em>TypeScript cheat sheet PDF</em></p>
<h2 id="heading-what-is-typescript">What is TypeScript?</h2>
<p>TypeScript is a superset of JavaScript, meaning that it does everything that JavaScript does, but with some added features.</p>
<p>The main reason for using TypeScript is to add static typing to JavaScript. Static typing means that the type of a variable cannot be changed at any point in a program. It can prevent a LOT of bugs!</p>
<p>On the other hand, JavaScript is a dynamically typed language, meaning variables can change type. Here's an example:</p>
<pre><code class="lang-ts"><span class="hljs-comment">// JavaScript</span>
<span class="hljs-keyword">let</span> foo = <span class="hljs-string">"hello"</span>;
foo = <span class="hljs-number">55</span>; <span class="hljs-comment">// foo has changed type from a string to a number - no problem</span>

<span class="hljs-comment">// TypeScript</span>
<span class="hljs-keyword">let</span> foo = <span class="hljs-string">"hello"</span>;
foo = <span class="hljs-number">55</span>; <span class="hljs-comment">// ERROR - foo cannot change from string to number</span>
</code></pre>
<p>TypeScript cannot be understood by browsers, so it has to be compiled into JavaScript by the TypeScript Compiler (TSC) – which we'll discuss soon.</p>
<h2 id="heading-is-typescript-worth-it">Is TypeScript worth it?</h2>
<h3 id="heading-why-you-should-use-typescript">Why you should use TypeScript</h3>
<ul>
<li>Research has shown that TypeScript can spot 15% of common bugs.</li>
<li>Readability – it is easier to see what the code it supposed to do. And when working in a team, it is easier to see what the other developers intended to.</li>
<li>It's popular – knowing TypeScript will enable you to apply to more good jobs.</li>
<li>Learning TypeScript will give you a better understanding, and a new perspective, on JavaScript.</li>
</ul>
<p><a target="_blank" href="https://www.doabledanny.com/why-typescript-over-javascript">Here's a short article I wrote demonstrating how TypeScript can prevent irritating bugs</a>.</p>
<h3 id="heading-drawbacks-of-typescript">Drawbacks of TypeScript</h3>
<ul>
<li>TypeScript takes longer to write than JavaScript, as you have to specify types, so for smaller solo projects it might not be worth using it.</li>
<li>TypeScript has to be compiled – which can take time, especially in larger projects.</li>
</ul>
<p>But the extra time that you have to spend writing more precise code and compiling will be more than saved by how many fewer bugs you'll have in your code. </p>
<p>For many projects – especially medium to large projects – TypeScript will save you lots of time and headaches.</p>
<p>And if you already know JavaScript, TypeScript won't be too hard to learn. It's a great tool to have in your arsenal.</p>
<h2 id="heading-how-to-set-up-a-typescript-project">How to Set Up a TypeScript Project</h2>
<h3 id="heading-install-node-and-the-typescript-compiler">Install Node and the TypeScript Compiler</h3>
<p>First, ensure you have <a target="_blank" href="https://nodejs.org/en/download/">Node</a> installed globally on your machine.</p>
<p>Then install the TypeScript compiler globally on your machine by running the following command: </p>
<pre><code class="lang-bash">npm i -g typescript
</code></pre>
<p>To check if the installation is successful (it will return the version number if successful):</p>
<pre><code class="lang-bash">tsc -v
</code></pre>
<h3 id="heading-how-to-compile-typescript">How to Compile TypeScript</h3>
<p>Open up your text editor and create a TypeScript file (for example, index.ts).</p>
<p>Write some JavaScript or TypeScript:</p>
<pre><code class="lang-ts"><span class="hljs-keyword">let</span> sport = <span class="hljs-string">'football'</span>;

<span class="hljs-keyword">let</span> id = <span class="hljs-number">5</span>;
</code></pre>
<p>We can now compile this down into JavaScript with the following command:</p>
<pre><code class="lang-bash">tsc index
</code></pre>
<p>TSC will compile the code into JavaScript and output it in a file called index.js:</p>
<pre><code class="lang-js"><span class="hljs-keyword">var</span> sport = <span class="hljs-string">'football'</span>;
<span class="hljs-keyword">var</span> id = <span class="hljs-number">5</span>;
</code></pre>
<p>If you want to specify the name of the output file:</p>
<p><code>tsc index.ts --outfile file-name.js</code></p>
<p>If you want TSC to compile your code automatically, whenever you make a change, add the "watch" flag:</p>
<p><code>tsc index.ts -w</code></p>
<p>An interesting thing about TypeScript is that it reports errors in your text editor whilst you are coding, but it will always compile your code – whether there are errors or not. </p>
<p>For example, the following causes TypeScript to immediately report an error:</p>
<pre><code><span class="hljs-keyword">var</span> sport = <span class="hljs-string">'football'</span>;
<span class="hljs-keyword">var</span> id = <span class="hljs-number">5</span>;

id = <span class="hljs-string">'5'</span>; <span class="hljs-comment">// Error: Type 'string' is not assignable to </span>
type <span class="hljs-string">'number'</span>.
</code></pre><p>But if we try to compile this code with <code>tsc index</code>, the code will still compile, despite the error. </p>
<p>This is an important property of TypeScript: it assumes that the developer knows more. Even though there's a TypeScript error, it doesn't get in your way of compiling the code. It tells you there's an error, but it's up to you whether you do anything about it.</p>
<h3 id="heading-how-to-set-up-the-ts-config-file">How to Set Up the ts config File</h3>
<p>The ts config file should be in the root directory of your project. In this file we can specify the root files, compiler options, and how strict we want TypeScript to be in checking our project.</p>
<p>First, create the ts config file:</p>
<p><code>tsc --init</code></p>
<p>You should now have a <code>tsconfig.json</code> file in the project root.</p>
<p>Here are some options that are good to be aware of (if using a frontend framework with TypeScript, most if this stuff is taken care of for you):</p>
<pre><code>{
    <span class="hljs-string">"compilerOptions"</span>: {
        ...
        <span class="hljs-comment">/* Modules */</span>
        <span class="hljs-string">"target"</span>: <span class="hljs-string">"es2016"</span>, <span class="hljs-comment">// Change to "ES2015" to compile to ES6</span>
        <span class="hljs-string">"rootDir"</span>: <span class="hljs-string">"./src"</span>, <span class="hljs-comment">// Where to compile from</span>
        <span class="hljs-string">"outDir"</span>: <span class="hljs-string">"./public"</span>, <span class="hljs-comment">// Where to compile to (usually the folder to be deployed to the web server)</span>

        <span class="hljs-comment">/* JavaScript Support */</span>
        <span class="hljs-string">"allowJs"</span>: <span class="hljs-literal">true</span>, <span class="hljs-comment">// Allow JavaScript files to be compiled</span>
        <span class="hljs-string">"checkJs"</span>: <span class="hljs-literal">true</span>, <span class="hljs-comment">// Type check JavaScript files and report errors</span>

        <span class="hljs-comment">/* Emit */</span>
        <span class="hljs-string">"sourceMap"</span>: <span class="hljs-literal">true</span>, <span class="hljs-comment">// Create source map files for emitted JavaScript files (good for debugging)</span>
         <span class="hljs-string">"removeComments"</span>: <span class="hljs-literal">true</span>, <span class="hljs-comment">// Don't emit comments</span>
    },
    <span class="hljs-string">"include"</span>: [<span class="hljs-string">"src"</span>] <span class="hljs-comment">// Ensure only files in src are compiled</span>
}
</code></pre><p>To compile everything and watch for changes:</p>
<p><code>tsc -w</code></p>
<p>Note: when input files are specified on the command line (for example, <code>tsc index</code>), <code>tsconfig.json</code> files are ignored.</p>
<h2 id="heading-types-in-typescript">Types in TypeScript</h2>
<h3 id="heading-primitive-types">Primitive types</h3>
<p>In JavaScript, a primitive value is data that is not an object and has no methods. There are 7 primitive data types:</p>
<ul>
<li>string</li>
<li>number</li>
<li>bigint</li>
<li>boolean</li>
<li>undefined</li>
<li>null</li>
<li>symbol</li>
</ul>
<p>Primitives are immutable: they can't be altered. It is important not to confuse a primitive itself with a variable assigned a primitive value. The variable may be reassigned a new value, but the existing value can't be changed in the ways that objects, arrays, and functions can be altered. </p>
<p>Here's an example:</p>
<pre><code><span class="hljs-keyword">let</span> name = <span class="hljs-string">'Danny'</span>;
name.toLowerCase();
<span class="hljs-built_in">console</span>.log(name); <span class="hljs-comment">// Danny - the string method didn't mutate the string</span>

<span class="hljs-keyword">let</span> arr = [<span class="hljs-number">1</span>, <span class="hljs-number">3</span>, <span class="hljs-number">5</span>, <span class="hljs-number">7</span>];
arr.pop();
<span class="hljs-built_in">console</span>.log(arr); <span class="hljs-comment">// [1, 3, 5] - the array method mutated the array</span>

name = <span class="hljs-string">'Anna'</span> <span class="hljs-comment">// Assignment gives the primitive a new (not a mutated) value</span>
</code></pre><p>In JavaScript, all primitive values (apart from null and undefined) have object equivalents that wrap around the primitive values. These wrapper objects are String, Number, BigInt, Boolean, and Symbol. These wrapper objects provide the methods that allow the primitive values to be manipulated.</p>
<p>Back to TypeScript, we can set the type we want a variable to be be adding <code>: type</code> (called a "type annotation" or a "type signature") after declaring a variable. Examples:</p>
<pre><code class="lang-ts"><span class="hljs-keyword">let</span> id: <span class="hljs-built_in">number</span> = <span class="hljs-number">5</span>;
<span class="hljs-keyword">let</span> firstname: <span class="hljs-built_in">string</span> = <span class="hljs-string">'danny'</span>;
<span class="hljs-keyword">let</span> hasDog: <span class="hljs-built_in">boolean</span> = <span class="hljs-literal">true</span>;

<span class="hljs-keyword">let</span> unit: <span class="hljs-built_in">number</span>; <span class="hljs-comment">// Declare variable without assigning a value</span>
unit = <span class="hljs-number">5</span>;
</code></pre>
<p>But it's usually best to not explicitly state the type, as TypeScript automatically infers the type of a variable (type inference):</p>
<pre><code><span class="hljs-keyword">let</span> id = <span class="hljs-number">5</span>; <span class="hljs-comment">// TS knows it's a number</span>
<span class="hljs-keyword">let</span> firstname = <span class="hljs-string">'danny'</span>; <span class="hljs-comment">// TS knows it's a string</span>
<span class="hljs-keyword">let</span> hasDog = <span class="hljs-literal">true</span>; <span class="hljs-comment">// TS knows it's a boolean</span>

hasDog = <span class="hljs-string">'yes'</span>; <span class="hljs-comment">// ERROR</span>
</code></pre><p>We can also set a variable to be able to be a union type. <strong>A union type is a variable that can be assigned more than one type</strong>:</p>
<pre><code><span class="hljs-keyword">let</span> age: string | number;
age = <span class="hljs-number">26</span>;
age = <span class="hljs-string">'26'</span>;
</code></pre><h3 id="heading-reference-types">Reference Types</h3>
<p>In JavaScript, almost "everything" is an object. In fact (and confusingly), strings, numbers and booleans can be objects if defined with the <code>new</code> keyword:</p>
<pre><code><span class="hljs-keyword">let</span> firstname = <span class="hljs-keyword">new</span> <span class="hljs-built_in">String</span>(<span class="hljs-string">'Danny'</span>);
<span class="hljs-built_in">console</span>.log(firstname); <span class="hljs-comment">// String {'Danny'}</span>
</code></pre><p>But when we talk of reference types in JavaScript, we are referring to arrays, objects and functions.</p>
<h4 id="heading-caveat-primitive-vs-reference-types">Caveat: primitive vs reference types</h4>
<p>For those that have never studied primitive vs reference types, let's discuss the fundamental difference.</p>
<p>If a primitive type is assigned to a variable, we can think of that variable as <em>containing</em> the primitive value. Each primitive value is stored in a unique location in memory.</p>
<p>If we have two variables, x and y, and they both contain primitive data, then they are completely independent of each other:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/01/image-66.png" alt="Primitive data are stored in unique memory locations" width="600" height="400" loading="lazy">
<em>X and Y both contain unique independent primitive data</em></p>
<pre><code><span class="hljs-keyword">let</span> x = <span class="hljs-number">2</span>;
<span class="hljs-keyword">let</span> y = <span class="hljs-number">1</span>;

x = y;
y = <span class="hljs-number">100</span>;
<span class="hljs-built_in">console</span>.log(x); <span class="hljs-comment">// 1 (even though y changed to 100, x is still 1)</span>
</code></pre><p>This isn't the case with reference types. Reference types refer to a memory location where the object is stored.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/01/image-67.png" alt="Reference types memory locations" width="600" height="400" loading="lazy">
<em>point1 and point2 contain a reference to the address where the object is stored</em></p>
<pre><code class="lang-ts"><span class="hljs-keyword">let</span> point1 = { x: <span class="hljs-number">1</span>, y: <span class="hljs-number">1</span> };
<span class="hljs-keyword">let</span> point2 = point1;

point1.y = <span class="hljs-number">100</span>;
<span class="hljs-built_in">console</span>.log(point2.y); <span class="hljs-comment">// 100 (point1 and point2 refer to the same memory address where the point object is stored)</span>
</code></pre>
<p>That was a quick overview of primary vs reference types. Check out this article if you need a more thorough explanation: <a target="_blank" href="https://codeburst.io/explaining-value-vs-reference-in-javascript-647a975e12a0">Primitive vs reference types</a>.</p>
<h4 id="heading-arrays-in-typescript">Arrays in TypeScript</h4>
<p>In TypeScript, you can define what type of data an array can contain:</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> ids: number[] = [<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>]; <span class="hljs-comment">// can only contain numbers</span>
<span class="hljs-keyword">let</span> names: string[] = [<span class="hljs-string">'Danny'</span>, <span class="hljs-string">'Anna'</span>, <span class="hljs-string">'Bazza'</span>]; <span class="hljs-comment">// can only contain strings</span>
<span class="hljs-keyword">let</span> options: boolean[] = [<span class="hljs-literal">true</span>, <span class="hljs-literal">false</span>, <span class="hljs-literal">false</span>]; can only contain <span class="hljs-literal">true</span> or <span class="hljs-literal">false</span>
<span class="hljs-keyword">let</span> books: object[] = [
  { <span class="hljs-attr">name</span>: <span class="hljs-string">'Fooled by randomness'</span>, <span class="hljs-attr">author</span>: <span class="hljs-string">'Nassim Taleb'</span> },
  { <span class="hljs-attr">name</span>: <span class="hljs-string">'Sapiens'</span>, <span class="hljs-attr">author</span>: <span class="hljs-string">'Yuval Noah Harari'</span> },
]; <span class="hljs-comment">// can only contain objects</span>
<span class="hljs-keyword">let</span> arr: any[] = [<span class="hljs-string">'hello'</span>, <span class="hljs-number">1</span>, <span class="hljs-literal">true</span>]; <span class="hljs-comment">// any basically reverts TypeScript back into JavaScript</span>

ids.push(<span class="hljs-number">6</span>);
ids.push(<span class="hljs-string">'7'</span>); <span class="hljs-comment">// ERROR: Argument of type 'string' is not assignable to parameter of type 'number'.</span>
</code></pre>
<p>You can use union types to define arrays containing multiple types:</p>
<pre><code class="lang-ts"><span class="hljs-keyword">let</span> person: (<span class="hljs-built_in">string</span> | <span class="hljs-built_in">number</span> | <span class="hljs-built_in">boolean</span>)[] = [<span class="hljs-string">'Danny'</span>, <span class="hljs-number">1</span>, <span class="hljs-literal">true</span>];
person[<span class="hljs-number">0</span>] = <span class="hljs-number">100</span>;
person[<span class="hljs-number">1</span>] = {name: <span class="hljs-string">'Danny'</span>} <span class="hljs-comment">// Error - person array can't contain objects</span>
</code></pre>
<p>If you initialise a variable with a value, it's not necessary to explicitly state the type, as TypeScript will infer it:</p>
<pre><code class="lang-ts"><span class="hljs-keyword">let</span> person = [<span class="hljs-string">'Danny'</span>, <span class="hljs-number">1</span>, <span class="hljs-literal">true</span>]; <span class="hljs-comment">// This is identical to above example</span>
person[<span class="hljs-number">0</span>] = <span class="hljs-number">100</span>;
person[<span class="hljs-number">1</span>] = { name: <span class="hljs-string">'Danny'</span> }; <span class="hljs-comment">// Error - person array can't contain objects</span>
</code></pre>
<p>There is a special type of array that can be defined in TypeScript: Tuples. <strong>A tuple is an array with fixed size and known datatypes.</strong> They are stricter than regular arrays.</p>
<pre><code><span class="hljs-keyword">let</span> person: [string, number, boolean] = [<span class="hljs-string">'Danny'</span>, <span class="hljs-number">1</span>, <span class="hljs-literal">true</span>];
person[<span class="hljs-number">0</span>] = <span class="hljs-number">100</span>; <span class="hljs-comment">// Error - Value at index 0 can only be a string</span>
</code></pre><h4 id="heading-objects-in-typescript">Objects in TypeScript</h4>
<p>Objects in TypeScript must have all the correct properties and value types:</p>
<pre><code class="lang-ts"><span class="hljs-comment">// Declare a variable called person with a specific object type annotation</span>
<span class="hljs-keyword">let</span> person: {
  name: <span class="hljs-built_in">string</span>;
  location: <span class="hljs-built_in">string</span>;
  isProgrammer: <span class="hljs-built_in">boolean</span>;
};

<span class="hljs-comment">// Assign person to an object with all the necessary properties and value types</span>
person = {
  name: <span class="hljs-string">'Danny'</span>,
  location: <span class="hljs-string">'UK'</span>,
  isProgrammer: <span class="hljs-literal">true</span>,
};

person.isProgrammer = <span class="hljs-string">'Yes'</span>; <span class="hljs-comment">// ERROR: should be a boolean</span>


person = {
  name: <span class="hljs-string">'John'</span>,
  location: <span class="hljs-string">'US'</span>,
}; 
<span class="hljs-comment">// ERROR: missing the isProgrammer property</span>
</code></pre>
<p>When defining the signature of an object, you will usually use an <strong>interface</strong>. This is useful if we need to check that multiple objects have the same specific properties and value types<strong>:</strong></p>
<pre><code class="lang-ts"><span class="hljs-keyword">interface</span> Person {
  name: <span class="hljs-built_in">string</span>;
  location: <span class="hljs-built_in">string</span>;
  isProgrammer: <span class="hljs-built_in">boolean</span>;
}

<span class="hljs-keyword">let</span> person1: Person = {
  name: <span class="hljs-string">'Danny'</span>,
  location: <span class="hljs-string">'UK'</span>,
  isProgrammer: <span class="hljs-literal">true</span>,
};

<span class="hljs-keyword">let</span> person2: Person = {
  name: <span class="hljs-string">'Sarah'</span>,
  location: <span class="hljs-string">'Germany'</span>,
  isProgrammer: <span class="hljs-literal">false</span>,
};
</code></pre>
<p>We can also declare function properties with function signatures. We can do this using old-school common JavaScript functions (<code>sayHi</code>), or ES6 arrow functions (<code>sayBye</code>):</p>
<pre><code class="lang-ts"><span class="hljs-keyword">interface</span> Speech {
  sayHi(name: <span class="hljs-built_in">string</span>): <span class="hljs-built_in">string</span>;
  sayBye: <span class="hljs-function">(<span class="hljs-params">name: <span class="hljs-built_in">string</span></span>) =&gt;</span> <span class="hljs-built_in">string</span>;
}

<span class="hljs-keyword">let</span> sayStuff: Speech = {
  sayHi: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">name: <span class="hljs-built_in">string</span></span>) </span>{
    <span class="hljs-keyword">return</span> <span class="hljs-string">`Hi <span class="hljs-subst">${name}</span>`</span>;
  },
  sayBye: <span class="hljs-function">(<span class="hljs-params">name: <span class="hljs-built_in">string</span></span>) =&gt;</span> <span class="hljs-string">`Bye <span class="hljs-subst">${name}</span>`</span>,
};

<span class="hljs-built_in">console</span>.log(sayStuff.sayHi(<span class="hljs-string">'Heisenberg'</span>)); <span class="hljs-comment">// Hi Heisenberg</span>
<span class="hljs-built_in">console</span>.log(sayStuff.sayBye(<span class="hljs-string">'Heisenberg'</span>)); <span class="hljs-comment">// Bye Heisenberg</span>
</code></pre>
<p>Note that in the <code>sayStuff</code> object, <code>sayHi</code> or <code>sayBye</code> could be given an arrow function or a common JavaScript function – TypeScript doesn't care.</p>
<h4 id="heading-functions-in-typescript">Functions in TypeScript</h4>
<p>We can define what the types the function arguments should be, as well as the return type of the function:</p>
<pre><code class="lang-ts"><span class="hljs-comment">// Define a function called circle that takes a diam variable of type number, and returns a string</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">circle</span>(<span class="hljs-params">diam: <span class="hljs-built_in">number</span></span>): <span class="hljs-title">string</span> </span>{
  <span class="hljs-keyword">return</span> <span class="hljs-string">'The circumference is '</span> + <span class="hljs-built_in">Math</span>.PI * diam;
}

<span class="hljs-built_in">console</span>.log(circle(<span class="hljs-number">10</span>)); <span class="hljs-comment">// The circumference is 31.41592653589793</span>
</code></pre>
<p>The same function, but with an ES6 arrow function:</p>
<pre><code class="lang-ts"><span class="hljs-keyword">const</span> circle = (diam: <span class="hljs-built_in">number</span>): <span class="hljs-function"><span class="hljs-params">string</span> =&gt;</span> {
  <span class="hljs-keyword">return</span> <span class="hljs-string">'The circumference is '</span> + <span class="hljs-built_in">Math</span>.PI * diam;
};

<span class="hljs-built_in">console</span>.log(circle(<span class="hljs-number">10</span>)); <span class="hljs-comment">// The circumference is 31.41592653589793</span>
</code></pre>
<p>Notice how it isn't necessary to explicitly state that <code>circle</code> is a function; TypeScript infers it. TypeScript also infers the return type of the function, so it doesn't need to be stated either. Although, if the function is large, some developers like to explicitly state the return type for clarity.</p>
<pre><code class="lang-ts"><span class="hljs-comment">// Using explicit typing </span>
<span class="hljs-keyword">const</span> circle: <span class="hljs-built_in">Function</span> = (diam: <span class="hljs-built_in">number</span>): <span class="hljs-function"><span class="hljs-params">string</span> =&gt;</span> {
  <span class="hljs-keyword">return</span> <span class="hljs-string">'The circumference is '</span> + <span class="hljs-built_in">Math</span>.PI * diam;
};

<span class="hljs-comment">// Inferred typing - TypeScript sees that circle is a function that always returns a string, so no need to explicitly state it</span>
<span class="hljs-keyword">const</span> circle = <span class="hljs-function">(<span class="hljs-params">diam: <span class="hljs-built_in">number</span></span>) =&gt;</span> {
  <span class="hljs-keyword">return</span> <span class="hljs-string">'The circumference is '</span> + <span class="hljs-built_in">Math</span>.PI * diam;
};
</code></pre>
<p>We can add a question mark after a parameter to make it optional. Also notice below how <code>c</code> is a union type that can be a number or string:</p>
<pre><code class="lang-ts"><span class="hljs-keyword">const</span> add = <span class="hljs-function">(<span class="hljs-params">a: <span class="hljs-built_in">number</span>, b: <span class="hljs-built_in">number</span>, c?: <span class="hljs-built_in">number</span> | <span class="hljs-built_in">string</span></span>) =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(c);

  <span class="hljs-keyword">return</span> a + b;
};

<span class="hljs-built_in">console</span>.log(add(<span class="hljs-number">5</span>, <span class="hljs-number">4</span>, <span class="hljs-string">'I could pass a number, string, or nothing here!'</span>));
<span class="hljs-comment">// I could pass a number, string, or nothing here!</span>
<span class="hljs-comment">// 9</span>
</code></pre>
<p>A function that returns nothing is said to return void – a complete lack of any value. Below, the return type of void has been explicitly stated. But again, this isn't necessary as TypeScript will infer it.</p>
<pre><code class="lang-ts"><span class="hljs-keyword">const</span> logMessage = (msg: <span class="hljs-built_in">string</span>): <span class="hljs-function"><span class="hljs-params">void</span> =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'This is the message: '</span> + msg);
};

logMessage(<span class="hljs-string">'TypeScript is superb'</span>); <span class="hljs-comment">// This is the message: TypeScript is superb</span>
</code></pre>
<p>If we want to declare a function variable, but not define it (say exactly what it does), <strong>then use a function signature.</strong> Below, the function <code>sayHello</code> must follow the signature after the colon:</p>
<pre><code class="lang-ts"><span class="hljs-comment">// Declare the varible sayHello, and give it a function signature that takes a string and returns nothing.</span>
<span class="hljs-keyword">let</span> sayHello: <span class="hljs-function">(<span class="hljs-params">name: <span class="hljs-built_in">string</span></span>) =&gt;</span> <span class="hljs-built_in">void</span>;

<span class="hljs-comment">// Define the function, satisfying its signature</span>
sayHello = <span class="hljs-function">(<span class="hljs-params">name</span>) =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Hello '</span> + name);
};

sayHello(<span class="hljs-string">'Danny'</span>); <span class="hljs-comment">// Hello Danny</span>
</code></pre>
<h4 id="heading-heres-an-interactive-scrim-to-help-you-learn-more-about-functions-in-typescript">Here's an interactive scrim to help you learn more about functions in TypeScript:</h4>
<div class="embed-wrapper"><iframe src="https://scrimba.com/scrim/cob6c429eb261c1c2a8506801?embed=freecodecamp,mini-header" width="100%" height="480" title="Embedded content" loading="lazy"></iframe></div>

<h3 id="heading-dynamic-any-types">Dynamic (any) types</h3>
<p>Using the <code>any</code> type, we can basically revert TypeScript back into JavaScript:</p>
<pre><code class="lang-ts"><span class="hljs-keyword">let</span> age: <span class="hljs-built_in">any</span> = <span class="hljs-string">'100'</span>;
age = <span class="hljs-number">100</span>;
age = {
  years: <span class="hljs-number">100</span>,
  months: <span class="hljs-number">2</span>,
};
</code></pre>
<p>It's recommended to avoid using the <code>any</code> type as much as you can, as it prevents TypeScript from doing its job – and can lead to bugs.</p>
<h3 id="heading-type-aliases">Type Aliases</h3>
<p>Type Aliases can reduce code duplication, keeping our code DRY. Below, we can see that the <code>PersonObject</code> type alias has prevented repetition, and acts as a single source of truth for what data a person object should contain.</p>
<pre><code class="lang-ts"><span class="hljs-keyword">type</span> StringOrNumber = <span class="hljs-built_in">string</span> | <span class="hljs-built_in">number</span>;

<span class="hljs-keyword">type</span> PersonObject = {
  name: <span class="hljs-built_in">string</span>;
  id: StringOrNumber;
};

<span class="hljs-keyword">const</span> person1: PersonObject = {
  name: <span class="hljs-string">'John'</span>,
  id: <span class="hljs-number">1</span>,
};

<span class="hljs-keyword">const</span> person2: PersonObject = {
  name: <span class="hljs-string">'Delia'</span>,
  id: <span class="hljs-number">2</span>,
};

<span class="hljs-keyword">const</span> sayHello = <span class="hljs-function">(<span class="hljs-params">person: PersonObject</span>) =&gt;</span> {
  <span class="hljs-keyword">return</span> <span class="hljs-string">'Hi '</span> + person.name;
};

<span class="hljs-keyword">const</span> sayGoodbye = <span class="hljs-function">(<span class="hljs-params">person: PersonObject</span>) =&gt;</span> {
  <span class="hljs-keyword">return</span> <span class="hljs-string">'Seeya '</span> + person.name;
};
</code></pre>
<h3 id="heading-the-dom-and-type-casting">The DOM and type casting</h3>
<p>TypeScript doesn't have access to the DOM like JavaScript. This means that whenever we try to access DOM elements, TypeScript is never sure that they actually exist.</p>
<p>The below example shows the problem:</p>
<pre><code class="lang-ts"><span class="hljs-keyword">const</span> link = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">'a'</span>);

<span class="hljs-built_in">console</span>.log(link.href); <span class="hljs-comment">// ERROR: Object is possibly 'null'. TypeScript can't be sure the anchor tag exists, as it can't access the DOM</span>
</code></pre>
<p>With the non-null assertion operator (!) we can tell the compiler explicitly that an expression has value other than <code>null</code> or <code>undefined</code>. This is can be useful when the compiler cannot infer the type with certainty, but we have more information than the compiler.</p>
<pre><code class="lang-ts"><span class="hljs-comment">// Here we are telling TypeScript that we are certain that this anchor tag exists</span>
<span class="hljs-keyword">const</span> link = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">'a'</span>)!;

<span class="hljs-built_in">console</span>.log(link.href); <span class="hljs-comment">// www.freeCodeCamp.org</span>
</code></pre>
<p>Notice how we didn't have to state the type of the <code>link</code> variable. This is because TypeScript can clearly see (via Type Inference) that it is of type <code>HTMLAnchorElement</code>.</p>
<p>But what if we needed to select a DOM element by its class or id? TypeScript can't infer the type, as it could be anything.</p>
<pre><code class="lang-ts"><span class="hljs-keyword">const</span> form = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'signup-form'</span>);

<span class="hljs-built_in">console</span>.log(form.method);
<span class="hljs-comment">// ERROR: Object is possibly 'null'.</span>
<span class="hljs-comment">// ERROR: Property 'method' does not exist on type 'HTMLElement'.</span>
</code></pre>
<p>Above, we get two errors. We need to tell TypeScript that we are certain <code>form</code> exists, and that we know it is of type <code>HTMLFormElement</code>. We do this with type casting:</p>
<pre><code class="lang-ts"><span class="hljs-keyword">const</span> form = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'signup-form'</span>) <span class="hljs-keyword">as</span> HTMLFormElement;

<span class="hljs-built_in">console</span>.log(form.method); <span class="hljs-comment">// post</span>
</code></pre>
<p>And TypeScript is happy!</p>
<p>TypeScript also has an Event object built in. So, if we add a submit event listener to our form, TypeScript will give us an error if we call any methods that aren't part of the Event object. Check out how cool TypeScript is – it can tell us when we've made a spelling mistake:</p>
<pre><code class="lang-ts"><span class="hljs-keyword">const</span> form = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'signup-form'</span>) <span class="hljs-keyword">as</span> HTMLFormElement;

form.addEventListener(<span class="hljs-string">'submit'</span>, <span class="hljs-function">(<span class="hljs-params">e: Event</span>) =&gt;</span> {
  e.preventDefault(); <span class="hljs-comment">// prevents the page from refreshing</span>

  <span class="hljs-built_in">console</span>.log(e.tarrget); <span class="hljs-comment">// ERROR: Property 'tarrget' does not exist on type 'Event'. Did you mean 'target'?</span>
});
</code></pre>
<h3 id="heading-heres-an-interactive-scrim-to-help-you-learn-more-about-types-in-typescript">Here's an interactive scrim to help you learn more about types in TypeScript:</h3>
<div class="embed-wrapper"><iframe src="https://scrimba.com/scrim/co84a432fa0e3ae761c178813?embed=freecodecamp,mini-header" width="100%" height="480" title="Embedded content" loading="lazy"></iframe></div>

<h2 id="heading-classes-in-typescript">Classes in TypeScript</h2>
<p>We can define the types that each piece of data should be in a class:</p>
<pre><code class="lang-ts"><span class="hljs-keyword">class</span> Person {
  name: <span class="hljs-built_in">string</span>;
  isCool: <span class="hljs-built_in">boolean</span>;
  pets: <span class="hljs-built_in">number</span>;

  <span class="hljs-keyword">constructor</span>(<span class="hljs-params">n: <span class="hljs-built_in">string</span>, c: <span class="hljs-built_in">boolean</span>, p: <span class="hljs-built_in">number</span></span>) {
    <span class="hljs-built_in">this</span>.name = n;
    <span class="hljs-built_in">this</span>.isCool = c;
    <span class="hljs-built_in">this</span>.pets = p;
  }

  sayHello() {
    <span class="hljs-keyword">return</span> <span class="hljs-string">`Hi, my name is <span class="hljs-subst">${<span class="hljs-built_in">this</span>.name}</span> and I have <span class="hljs-subst">${<span class="hljs-built_in">this</span>.pets}</span> pets`</span>;
  }
}

<span class="hljs-keyword">const</span> person1 = <span class="hljs-keyword">new</span> Person(<span class="hljs-string">'Danny'</span>, <span class="hljs-literal">false</span>, <span class="hljs-number">1</span>);
<span class="hljs-keyword">const</span> person2 = <span class="hljs-keyword">new</span> Person(<span class="hljs-string">'Sarah'</span>, <span class="hljs-string">'yes'</span>, <span class="hljs-number">6</span>); <span class="hljs-comment">// ERROR: Argument of type 'string' is not assignable to parameter of type 'boolean'.</span>

<span class="hljs-built_in">console</span>.log(person1.sayHello()); <span class="hljs-comment">// Hi, my name is Danny and I have 1 pets</span>
</code></pre>
<p>We could then create a <code>people</code> array that only includes objects constructed from the <code>Person</code> class:</p>
<pre><code class="lang-ts"><span class="hljs-keyword">let</span> People: Person[] = [person1, person2];
</code></pre>
<p>We can add access modifiers to the properties of a class. TypeScript also provides a new access modifier called <code>readonly</code>.</p>
<pre><code class="lang-ts"><span class="hljs-keyword">class</span> Person {
  <span class="hljs-keyword">readonly</span> name: <span class="hljs-built_in">string</span>; <span class="hljs-comment">// This property is immutable - it can only be read</span>
  <span class="hljs-keyword">private</span> isCool: <span class="hljs-built_in">boolean</span>; <span class="hljs-comment">// Can only access or modify from methods within this class</span>
  <span class="hljs-keyword">protected</span> email: <span class="hljs-built_in">string</span>; <span class="hljs-comment">// Can access or modify from this class and subclasses</span>
  <span class="hljs-keyword">public</span> pets: <span class="hljs-built_in">number</span>; <span class="hljs-comment">// Can access or modify from anywhere - including outside the class</span>

  <span class="hljs-keyword">constructor</span>(<span class="hljs-params">n: <span class="hljs-built_in">string</span>, c: <span class="hljs-built_in">boolean</span>, e: <span class="hljs-built_in">string</span>, p: <span class="hljs-built_in">number</span></span>) {
    <span class="hljs-built_in">this</span>.name = n;
    <span class="hljs-built_in">this</span>.isCool = c;
    <span class="hljs-built_in">this</span>.email = e;
    <span class="hljs-built_in">this</span>.pets = p;
  }

  sayMyName() {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Your not Heisenberg, you're <span class="hljs-subst">${<span class="hljs-built_in">this</span>.name}</span>`</span>);
  }
}

<span class="hljs-keyword">const</span> person1 = <span class="hljs-keyword">new</span> Person(<span class="hljs-string">'Danny'</span>, <span class="hljs-literal">false</span>, <span class="hljs-string">'dan@e.com'</span>, <span class="hljs-number">1</span>);
<span class="hljs-built_in">console</span>.log(person1.name); <span class="hljs-comment">// Fine</span>
person1.name = <span class="hljs-string">'James'</span>; <span class="hljs-comment">// Error: read only</span>
<span class="hljs-built_in">console</span>.log(person1.isCool); <span class="hljs-comment">// Error: private property - only accessible within Person class</span>
<span class="hljs-built_in">console</span>.log(person1.email); <span class="hljs-comment">// Error: protected property - only accessible within Person class and its subclasses</span>
<span class="hljs-built_in">console</span>.log(person1.pets); <span class="hljs-comment">// Public property - so no problem</span>
</code></pre>
<p>We can make our code more concise by constructing class properties this way:</p>
<pre><code class="lang-ts"><span class="hljs-keyword">class</span> Person {
  <span class="hljs-keyword">constructor</span>(<span class="hljs-params">
    <span class="hljs-keyword">readonly</span> name: <span class="hljs-built_in">string</span>,
    <span class="hljs-keyword">private</span> isCool: <span class="hljs-built_in">boolean</span>,
    <span class="hljs-keyword">protected</span> email: <span class="hljs-built_in">string</span>,
    <span class="hljs-keyword">public</span> pets: <span class="hljs-built_in">number</span>
  </span>) {}

  sayMyName() {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Your not Heisenberg, you're <span class="hljs-subst">${<span class="hljs-built_in">this</span>.name}</span>`</span>);
  }
}

<span class="hljs-keyword">const</span> person1 = <span class="hljs-keyword">new</span> Person(<span class="hljs-string">'Danny'</span>, <span class="hljs-literal">false</span>, <span class="hljs-string">'dan@e.com'</span>, <span class="hljs-number">1</span>);
<span class="hljs-built_in">console</span>.log(person1.name); <span class="hljs-comment">// Danny</span>
</code></pre>
<p>Writing it the above way, the properties are automatically assigned in the constructor – saving us from having to write them all out.</p>
<p>Note that if we omit the access modifier, by default the property will be public.</p>
<p>Classes can also be extended, just like in regular JavaScript:</p>
<pre><code class="lang-ts"><span class="hljs-keyword">class</span> Programmer <span class="hljs-keyword">extends</span> Person {
  programmingLanguages: <span class="hljs-built_in">string</span>[];

  <span class="hljs-keyword">constructor</span>(<span class="hljs-params">
    name: <span class="hljs-built_in">string</span>,
    isCool: <span class="hljs-built_in">boolean</span>,
    email: <span class="hljs-built_in">string</span>,
    pets: <span class="hljs-built_in">number</span>,
    pL: <span class="hljs-built_in">string</span>[]
  </span>) {
    <span class="hljs-comment">// The super call must supply all parameters for base (Person) class, as the constructor is not inherited.</span>
    <span class="hljs-built_in">super</span>(name, isCool, email, pets);
    <span class="hljs-built_in">this</span>.programmingLanguages = pL;
  }
}
</code></pre>
<p><a target="_blank" href="https://www.typescriptlang.org/docs/handbook/2/classes.html">For more on classes, refer to the official TypeScript docs</a>.</p>
<h3 id="heading-heres-an-interactive-scrim-to-help-you-learn-more-about-classes-in-typescript">Here's an interactive scrim to help you learn more about classes in TypeScript:</h3>
<div class="embed-wrapper"><iframe src="https://scrimba.com/scrim/co52541818fd74bc8663ac381?embed=freecodecamp,mini-header" width="100%" height="480" title="Embedded content" loading="lazy"></iframe></div>

<h2 id="heading-modules-in-typescript">Modules in TypeScript</h2>
<p>In JavaScript, a module is  just a file containing related code. Functionality can be imported and exported between modules, keeping the code well organized.</p>
<p>TypeScript also supports modules. The TypeScript files will compile down into multiple JavaScript files.</p>
<p>In the <code>tsconfig.json</code> file, change the following options to support modern importing and exporting:</p>
<pre><code class="lang-ts"> <span class="hljs-string">"target"</span>: <span class="hljs-string">"es2016"</span>,
 <span class="hljs-string">"module"</span>: <span class="hljs-string">"es2015"</span>
</code></pre>
<p>(Although, for Node projects you very likely want <code>"module": "CommonJS"</code> – Node doesn't  yet support modern importing/exporting.)</p>
<p>Now, in your HTML file, change the script import to be of type module:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"module"</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"/public/script.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<p>We can now import and export files using ES6:</p>
<pre><code class="lang-ts"><span class="hljs-comment">// src/hello.ts</span>
<span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">sayHi</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Hello there!'</span>);
}

<span class="hljs-comment">// src/script.ts</span>
<span class="hljs-keyword">import</span> { sayHi } <span class="hljs-keyword">from</span> <span class="hljs-string">'./hello.js'</span>;

sayHi(); <span class="hljs-comment">// Hello there!</span>
</code></pre>
<p>Note: always import as a JavaScript file, even in TypeScript files.</p>
<h2 id="heading-interfaces-in-typescript">Interfaces in TypeScript</h2>
<p>Interfaces define how an object should look:</p>
<pre><code class="lang-ts"><span class="hljs-keyword">interface</span> Person {
  name: <span class="hljs-built_in">string</span>;
  age: <span class="hljs-built_in">number</span>;
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">sayHi</span>(<span class="hljs-params">person: Person</span>) </span>{
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Hi <span class="hljs-subst">${person.name}</span>`</span>);
}

sayHi({
  name: <span class="hljs-string">'John'</span>,
  age: <span class="hljs-number">48</span>,
}); <span class="hljs-comment">// Hi John</span>
</code></pre>
<p>You can also define an object type using a type alias:</p>
<pre><code class="lang-ts"><span class="hljs-keyword">type</span> Person = {
  name: <span class="hljs-built_in">string</span>;
  age: <span class="hljs-built_in">number</span>;
};

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">sayHi</span>(<span class="hljs-params">person: Person</span>) </span>{
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Hi <span class="hljs-subst">${person.name}</span>`</span>);
}

sayHi({
  name: <span class="hljs-string">'John'</span>,
  age: <span class="hljs-number">48</span>,
}); <span class="hljs-comment">// Hi John</span>
</code></pre>
<p>Or an object type could be defined anonymously:</p>
<pre><code class="lang-ts"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">sayHi</span>(<span class="hljs-params">person: { name: <span class="hljs-built_in">string</span>; age: <span class="hljs-built_in">number</span> }</span>) </span>{
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Hi <span class="hljs-subst">${person.name}</span>`</span>);
}

sayHi({
  name: <span class="hljs-string">'John'</span>,
  age: <span class="hljs-number">48</span>,
}); <span class="hljs-comment">// Hi John</span>
</code></pre>
<p>Interfaces are very similar to type aliases, and in many cases you can use either. The key distinction is that type aliases cannot be reopened to add new properties, vs an interface which is always extendable. </p>
<p>The following examples are taken from the <a target="_blank" href="https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#differences-between-type-aliases-and-interfaces">TypeScript docs</a>.</p>
<p>Extending an interface:</p>
<pre><code class="lang-ts"><span class="hljs-keyword">interface</span> Animal {
  name: <span class="hljs-built_in">string</span>
}

<span class="hljs-keyword">interface</span> Bear <span class="hljs-keyword">extends</span> Animal {
  honey: <span class="hljs-built_in">boolean</span>
}

<span class="hljs-keyword">const</span> bear: Bear = {
  name: <span class="hljs-string">"Winnie"</span>,
  honey: <span class="hljs-literal">true</span>,
}
</code></pre>
<p>Extending a type via intersections:</p>
<pre><code class="lang-ts"><span class="hljs-keyword">type</span> Animal = {
  name: <span class="hljs-built_in">string</span>
}

<span class="hljs-keyword">type</span> Bear = Animal &amp; {
  honey: <span class="hljs-built_in">boolean</span>
}

<span class="hljs-keyword">const</span> bear: Bear = {
  name: <span class="hljs-string">"Winnie"</span>,
  honey: <span class="hljs-literal">true</span>,
}
</code></pre>
<p>Adding new fields to an existing interface:</p>
<pre><code class="lang-ts"><span class="hljs-keyword">interface</span> Animal {
  name: <span class="hljs-built_in">string</span>
}

<span class="hljs-comment">// Re-opening the Animal interface to add a new field</span>
<span class="hljs-keyword">interface</span> Animal {
  tail: <span class="hljs-built_in">boolean</span>
}

<span class="hljs-keyword">const</span> dog: Animal = {
  name: <span class="hljs-string">"Bruce"</span>,
  tail: <span class="hljs-literal">true</span>,
}
</code></pre>
<p>Here's the key difference: a type cannot be changed after being created:</p>
<pre><code class="lang-ts"><span class="hljs-keyword">type</span> Animal = {
  name: <span class="hljs-built_in">string</span>
}

<span class="hljs-keyword">type</span> Animal = {
  tail: <span class="hljs-built_in">boolean</span>
}
<span class="hljs-comment">// ERROR: Duplicate identifier 'Animal'.</span>
</code></pre>
<p>As a rule of thumb, the TypeScript docs recommend using interfaces to define objects, until you need to use the features of a type.</p>
<p>Interfaces can also define function signatures:</p>
<pre><code>interface Person {
  <span class="hljs-attr">name</span>: string
  <span class="hljs-attr">age</span>: number
  speak(sentence: string): <span class="hljs-keyword">void</span>
}

<span class="hljs-keyword">const</span> person1: Person = {
  <span class="hljs-attr">name</span>: <span class="hljs-string">"John"</span>,
  <span class="hljs-attr">age</span>: <span class="hljs-number">48</span>,
  <span class="hljs-attr">speak</span>: <span class="hljs-function"><span class="hljs-params">sentence</span> =&gt;</span> <span class="hljs-built_in">console</span>.log(sentence),
}
</code></pre><p>You may be wondering why we would use an interface over a class in the above example.  </p>
<p>One advantage of using an interface is that it is only used by TypeScript, not JavaScript. This means that it won't get compiled and add bloat to your JavaScript. Classes are features of JavaScript, so it would get compiled.</p>
<p>Also, a class is essentially an <em>object factory</em> (that is, a blueprint of what an object is supposed to look like and then implemented), whereas an interface is a structure used solely for <em>type-checking</em>.</p>
<p>While a class may have initialized properties and methods to help create objects, an interface essentially defines the properties and type an object can have.</p>
<h3 id="heading-interfaces-with-classes">Interfaces with classes</h3>
<p>We can tell a class that it must contain certain properties and methods by implementing an interface:</p>
<pre><code class="lang-ts"><span class="hljs-keyword">interface</span> HasFormatter {
  format(): <span class="hljs-built_in">string</span>;
}

<span class="hljs-keyword">class</span> Person <span class="hljs-keyword">implements</span> HasFormatter {
  <span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">public</span> username: <span class="hljs-built_in">string</span>, <span class="hljs-keyword">protected</span> password: <span class="hljs-built_in">string</span></span>) {}

  format() {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.username.toLocaleLowerCase();
  }
}

<span class="hljs-comment">// Must be objects that implement the HasFormatter interface</span>
<span class="hljs-keyword">let</span> person1: HasFormatter;
<span class="hljs-keyword">let</span> person2: HasFormatter;

person1 = <span class="hljs-keyword">new</span> Person(<span class="hljs-string">'Danny'</span>, <span class="hljs-string">'password123'</span>);
person2 = <span class="hljs-keyword">new</span> Person(<span class="hljs-string">'Jane'</span>, <span class="hljs-string">'TypeScripter1990'</span>);

<span class="hljs-built_in">console</span>.log(person1.format()); <span class="hljs-comment">// danny</span>
</code></pre>
<p>Ensure that <code>people</code> is an array of objects that implement <code>HasFormatter</code> (ensures that each person has the format method):</p>
<pre><code class="lang-ts"><span class="hljs-keyword">let</span> people: HasFormatter[] = [];
people.push(person1);
people.push(person2);
</code></pre>
<h2 id="heading-literal-types-in-typescript">Literal types in TypeScript</h2>
<p>In addition to the general types <code>string</code> and <code>number</code>, we can refer to specific strings and numbers in type positions:</p>
<pre><code><span class="hljs-comment">// Union type with a literal type in each position</span>
<span class="hljs-keyword">let</span> favouriteColor: <span class="hljs-string">'red'</span> | <span class="hljs-string">'blue'</span> | <span class="hljs-string">'green'</span> | <span class="hljs-string">'yellow'</span>;

favouriteColor = <span class="hljs-string">'blue'</span>;
favouriteColor = <span class="hljs-string">'crimson'</span>; <span class="hljs-comment">// ERROR: Type '"crimson"' is not assignable to type '"red" | "blue" | "green" | "yellow"'.</span>
</code></pre><h3 id="heading-heres-an-interactive-scrim-to-help-you-learn-more-about-literal-types-in-typescript">Here's an interactive scrim to help you learn more about literal types in TypeScript:</h3>
<div class="embed-wrapper"><iframe src="https://scrimba.com/scrim/coe7d49b596c09a2f4b75c73d?embed=freecodecamp,mini-header" width="100%" height="480" title="Embedded content" loading="lazy"></iframe></div>

<h2 id="heading-generics">Generics</h2>
<p>Generics allow you to create a component that can work over a variety of types, rather than a single one, <strong>which helps to make the component more reusable.</strong></p>
<p>Let's go through an example to show you what that means...</p>
<p>The <code>addID</code> function accepts any object, and returns a new object with all the properties and values of the passed in object, plus an <code>id</code> property with random value between 0 and 1000. In short, it gives any object an ID.</p>
<pre><code class="lang-ts"> <span class="hljs-keyword">const</span> addID = <span class="hljs-function">(<span class="hljs-params">obj: <span class="hljs-built_in">object</span></span>) =&gt;</span> {
  <span class="hljs-keyword">let</span> id = <span class="hljs-built_in">Math</span>.floor(<span class="hljs-built_in">Math</span>.random() * <span class="hljs-number">1000</span>);

  <span class="hljs-keyword">return</span> { ...obj, id };
};

<span class="hljs-keyword">let</span> person1 = addID({ name: <span class="hljs-string">'John'</span>, age: <span class="hljs-number">40</span> });

<span class="hljs-built_in">console</span>.log(person1.id); <span class="hljs-comment">// 271</span>
<span class="hljs-built_in">console</span>.log(person1.name); <span class="hljs-comment">// ERROR: Property 'name' does not exist on type '{ id: number; }'.</span>
</code></pre>
<p>As you can see, TypeScript gives an error when we try to access the <code>name</code> property. This is because when we pass in an object to <code>addID</code>, we are not specifying what properties this object should have – so TypeScript has no idea what properties the object has (it hasn't "captured" them). So, the only property that TypeScript knows is on the returned object is <code>id</code>.</p>
<p>So, how can we pass in any object to <code>addID</code>, but still tell TypeScript what properties and values the object has? We can use a <em>generic</em>, <code>&lt;T&gt;</code> – where <code>T</code> is known as the <em>type parameter</em>:</p>
<pre><code class="lang-ts"><span class="hljs-comment">// &lt;T&gt; is just the convention - e.g. we could use &lt;X&gt; or &lt;A&gt;</span>
<span class="hljs-keyword">const</span> addID = &lt;T&gt;<span class="hljs-function">(<span class="hljs-params">obj: T</span>) =&gt;</span> {
  <span class="hljs-keyword">let</span> id = <span class="hljs-built_in">Math</span>.floor(<span class="hljs-built_in">Math</span>.random() * <span class="hljs-number">1000</span>);

  <span class="hljs-keyword">return</span> { ...obj, id };
};
</code></pre>
<p>What does this do? Well, now when we pass an object into <code>addID</code>, we have told TypeScript to capture the type – so <code>T</code> becomes whatever type we pass in. <code>addID</code> will now know what properties are on the object we pass in.</p>
<p>But, we now have a problem: anything can be passed into <code>addID</code> and TypeScript will capture the type and report no problem:</p>
<pre><code class="lang-ts"><span class="hljs-keyword">let</span> person1 = addID({ name: <span class="hljs-string">'John'</span>, age: <span class="hljs-number">40</span> });
<span class="hljs-keyword">let</span> person2 = addID(<span class="hljs-string">'Sally'</span>); <span class="hljs-comment">// Pass in a string - no problem</span>

<span class="hljs-built_in">console</span>.log(person1.id); <span class="hljs-comment">// 271</span>
<span class="hljs-built_in">console</span>.log(person1.name); <span class="hljs-comment">// John</span>

<span class="hljs-built_in">console</span>.log(person2.id);
<span class="hljs-built_in">console</span>.log(person2.name); <span class="hljs-comment">// ERROR: Property 'name' does not exist on type '"Sally" &amp; { id: number; }'.</span>
</code></pre>
<p>When we passed in a string, TypeScript saw no issue. It only reported an error when we tried to access the <code>name</code> property. So, we need a constraint: we need to tell TypeScript that only objects should be accepted, by making our generic type, <code>T</code>, an extension of <code>object</code>:</p>
<pre><code class="lang-ts"><span class="hljs-keyword">const</span> addID = &lt;T <span class="hljs-keyword">extends</span> <span class="hljs-built_in">object</span>&gt;<span class="hljs-function">(<span class="hljs-params">obj: T</span>) =&gt;</span> {
  <span class="hljs-keyword">let</span> id = <span class="hljs-built_in">Math</span>.floor(<span class="hljs-built_in">Math</span>.random() * <span class="hljs-number">1000</span>);

  <span class="hljs-keyword">return</span> { ...obj, id };
};

<span class="hljs-keyword">let</span> person1 = addID({ name: <span class="hljs-string">'John'</span>, age: <span class="hljs-number">40</span> });
<span class="hljs-keyword">let</span> person2 = addID(<span class="hljs-string">'Sally'</span>); <span class="hljs-comment">// ERROR: Argument of type 'string' is not assignable to parameter of type 'object'.</span>
</code></pre>
<p>The error is caught straight away – perfect... well, not quite. In JavaScript, arrays are objects, so we can still get away with passing in an array:</p>
<pre><code class="lang-ts"><span class="hljs-keyword">let</span> person2 = addID([<span class="hljs-string">'Sally'</span>, <span class="hljs-number">26</span>]); <span class="hljs-comment">// Pass in an array - no problem</span>

<span class="hljs-built_in">console</span>.log(person2.id); <span class="hljs-comment">// 824</span>
<span class="hljs-built_in">console</span>.log(person2.name); <span class="hljs-comment">// Error: Property 'name' does not exist on type '(string | number)[] &amp; { id: number; }'.</span>
</code></pre>
<p>We could solve this by saying that the object argument should have a name property with string value:</p>
<pre><code class="lang-ts"><span class="hljs-keyword">const</span> addID = &lt;T <span class="hljs-keyword">extends</span> { name: <span class="hljs-built_in">string</span> }&gt;<span class="hljs-function">(<span class="hljs-params">obj: T</span>) =&gt;</span> {
  <span class="hljs-keyword">let</span> id = <span class="hljs-built_in">Math</span>.floor(<span class="hljs-built_in">Math</span>.random() * <span class="hljs-number">1000</span>);

  <span class="hljs-keyword">return</span> { ...obj, id };
};

<span class="hljs-keyword">let</span> person2 = addID([<span class="hljs-string">'Sally'</span>, <span class="hljs-number">26</span>]); <span class="hljs-comment">// ERROR: argument should have a name property with string value</span>
</code></pre>
<p>The type can also be passed in to <code>&lt;T&gt;</code>, as below – but this isn't necessary most of the time, as TypeScript will infer it.</p>
<pre><code class="lang-ts"><span class="hljs-comment">// Below, we have explicitly stated what type the argument should be between the angle brackets.</span>
<span class="hljs-keyword">let</span> person1 = addID&lt;{ name: <span class="hljs-built_in">string</span>; age: <span class="hljs-built_in">number</span> }&gt;({ name: <span class="hljs-string">'John'</span>, age: <span class="hljs-number">40</span> });
</code></pre>
<p><strong>Generics allow you to have type-safety in components where the arguments and return types are unknown ahead of time.</strong></p>
<p><strong>In TypeScript, generics are used when we want to describe a correspondence between two values.</strong> In the above example, the return type was related to the input type. We used a <em>generic</em> to describe the correspondence.</p>
<p>Another example: If we need a function that accepts multiple types, it is better to use a generic than the <code>any</code> type. Below shows the issue with using <code>any</code>:</p>
<pre><code class="lang-ts"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">logLength</span>(<span class="hljs-params">a: <span class="hljs-built_in">any</span></span>) </span>{
  <span class="hljs-built_in">console</span>.log(a.length); <span class="hljs-comment">// No error</span>
  <span class="hljs-keyword">return</span> a;
}

<span class="hljs-keyword">let</span> hello = <span class="hljs-string">'Hello world'</span>;
logLength(hello); <span class="hljs-comment">// 11</span>

<span class="hljs-keyword">let</span> howMany = <span class="hljs-number">8</span>;
logLength(howMany); <span class="hljs-comment">// undefined (but no TypeScript error - surely we want TypeScript to tell us we've tried to access a length property on a number!)</span>
</code></pre>
<p>We could try using a generic:</p>
<pre><code class="lang-ts"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">logLength</span>&lt;<span class="hljs-title">T</span>&gt;(<span class="hljs-params">a: T</span>) </span>{
  <span class="hljs-built_in">console</span>.log(a.length); <span class="hljs-comment">// ERROR: TypeScript isn't certain that `a` is a value with a length property</span>
  <span class="hljs-keyword">return</span> a;
}
</code></pre>
<p>At least we are now getting some feedback that we can use to tighten up our code.</p>
<p>Solution: use a generic that extends an interface that ensures every argument passed in has a length property:</p>
<pre><code class="lang-ts"><span class="hljs-keyword">interface</span> hasLength {
  length: <span class="hljs-built_in">number</span>;
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">logLength</span>&lt;<span class="hljs-title">T</span> <span class="hljs-title">extends</span> <span class="hljs-title">hasLength</span>&gt;(<span class="hljs-params">a: T</span>) </span>{
  <span class="hljs-built_in">console</span>.log(a.length);
  <span class="hljs-keyword">return</span> a;
}

<span class="hljs-keyword">let</span> hello = <span class="hljs-string">'Hello world'</span>;
logLength(hello); <span class="hljs-comment">// 11</span>

<span class="hljs-keyword">let</span> howMany = <span class="hljs-number">8</span>;
logLength(howMany); <span class="hljs-comment">// Error: numbers don't have length properties</span>
</code></pre>
<p>We could also write a function where the argument is an array of elements that all have a length property:</p>
<pre><code class="lang-ts"><span class="hljs-keyword">interface</span> hasLength {
  length: <span class="hljs-built_in">number</span>;
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">logLengths</span>&lt;<span class="hljs-title">T</span> <span class="hljs-title">extends</span> <span class="hljs-title">hasLength</span>&gt;(<span class="hljs-params">a: T[]</span>) </span>{
  a.forEach(<span class="hljs-function">(<span class="hljs-params">element</span>) =&gt;</span> {
    <span class="hljs-built_in">console</span>.log(element.length);
  });
}

<span class="hljs-keyword">let</span> arr = [
  <span class="hljs-string">'This string has a length prop'</span>,
  [<span class="hljs-string">'This'</span>, <span class="hljs-string">'arr'</span>, <span class="hljs-string">'has'</span>, <span class="hljs-string">'length'</span>],
  { material: <span class="hljs-string">'plastic'</span>, length: <span class="hljs-number">30</span> },
];

logLengths(arr);
<span class="hljs-comment">// 29</span>
<span class="hljs-comment">// 4</span>
<span class="hljs-comment">// 30</span>
</code></pre>
<p>Generics are an awesome feature of TypeScript!</p>
<h3 id="heading-generics-with-interfaces">Generics with interfaces</h3>
<p>When we don't know what type a certain value in an object will be ahead of time, we can use a generic to pass in the type:</p>
<pre><code class="lang-ts"><span class="hljs-comment">// The type, T, will be passed in</span>
<span class="hljs-keyword">interface</span> Person&lt;T&gt; {
  name: <span class="hljs-built_in">string</span>;
  age: <span class="hljs-built_in">number</span>;
  documents: T;
}

<span class="hljs-comment">// We have to pass in the type of `documents` - an array of strings in this case</span>
<span class="hljs-keyword">const</span> person1: Person&lt;<span class="hljs-built_in">string</span>[]&gt; = {
  name: <span class="hljs-string">'John'</span>,
  age: <span class="hljs-number">48</span>,
  documents: [<span class="hljs-string">'passport'</span>, <span class="hljs-string">'bank statement'</span>, <span class="hljs-string">'visa'</span>],
};

<span class="hljs-comment">// Again, we implement the `Person` interface, and pass in the type for documents - in this case a string</span>
<span class="hljs-keyword">const</span> person2: Person&lt;<span class="hljs-built_in">string</span>&gt; = {
  name: <span class="hljs-string">'Delia'</span>,
  age: <span class="hljs-number">46</span>,
  documents: <span class="hljs-string">'passport, P45'</span>,
};
</code></pre>
<h2 id="heading-enums-in-typescript">Enums in TypeScript</h2>
<p>Enums are a special feature that TypeScript brings to JavaScript. Enums allow us to define or declare a collection of related values, that can be numbers or strings, as a set of named constants.</p>
<pre><code class="lang-ts"><span class="hljs-built_in">enum</span> ResourceType {
  BOOK,
  AUTHOR,
  FILM,
  DIRECTOR,
  PERSON,
}

<span class="hljs-built_in">console</span>.log(ResourceType.BOOK); <span class="hljs-comment">// 0</span>
<span class="hljs-built_in">console</span>.log(ResourceType.AUTHOR); <span class="hljs-comment">// 1</span>

<span class="hljs-comment">// To start from 1</span>
<span class="hljs-built_in">enum</span> ResourceType {
  BOOK = <span class="hljs-number">1</span>,
  AUTHOR,
  FILM,
  DIRECTOR,
  PERSON,
}

<span class="hljs-built_in">console</span>.log(ResourceType.BOOK); <span class="hljs-comment">// 1</span>
<span class="hljs-built_in">console</span>.log(ResourceType.AUTHOR); <span class="hljs-comment">// 2</span>
</code></pre>
<p>By default, enums are number based – they store string values as numbers. But they can also be strings:</p>
<pre><code class="lang-ts"><span class="hljs-built_in">enum</span> Direction {
  Up = <span class="hljs-string">'Up'</span>,
  Right = <span class="hljs-string">'Right'</span>,
  Down = <span class="hljs-string">'Down'</span>,
  Left = <span class="hljs-string">'Left'</span>,
}

<span class="hljs-built_in">console</span>.log(Direction.Right); <span class="hljs-comment">// Right</span>
<span class="hljs-built_in">console</span>.log(Direction.Down); <span class="hljs-comment">// Down</span>
</code></pre>
<p>Enums are useful when we have a set of related constants. For example, instead of using non-descriptive numbers throughout your code, enums make code more readable with descriptive constants. </p>
<p>Enums can also prevent bugs, as when you type the name of the enum, intellisense will pop up and give you the list of possible options that can be selected.</p>
<h2 id="heading-typescript-strict-mode">TypeScript strict mode</h2>
<p>It is recommended to have all strict type-checking operations enabled in the <code>tsconfig.json</code> file. This will cause TypeScript to report more errors, but will help prevent many bugs from creeping into your application.</p>
<pre><code class="lang-ts"> <span class="hljs-comment">// tsconfig.json</span>
 <span class="hljs-string">"strict"</span>: <span class="hljs-literal">true</span>
</code></pre>
<p>Let's discuss a couple of the things that strict mode does: no implicit any, and strict null checks.</p>
<h3 id="heading-no-implicit-any">No implicit any</h3>
<p>In the function below, TypeScript has inferred that the parameter <code>a</code> is of <code>any</code> type. As you can see, when we pass in a number to this function, and try to log a <code>name</code> property, no error is reported. Not good.</p>
<pre><code class="lang-ts"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">logName</span>(<span class="hljs-params">a</span>) </span>{
  <span class="hljs-comment">// No error??</span>
  <span class="hljs-built_in">console</span>.log(a.name);
}

logName(<span class="hljs-number">97</span>);
</code></pre>
<p>With the <code>noImplicitAny</code> option turned on, TypeScript will instantly flag an error if we don't explicitly state the type of <code>a</code>:</p>
<pre><code class="lang-ts"><span class="hljs-comment">// ERROR: Parameter 'a' implicitly has an 'any' type.</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">logName</span>(<span class="hljs-params">a</span>) </span>{
  <span class="hljs-built_in">console</span>.log(a.name);
}
</code></pre>
<h3 id="heading-strict-null-checks">Strict null checks</h3>
<p>When the <code>strictNullChecks</code> option is false, TypeScript effectively ignores <code>null</code> and <code>undefined</code>. This can lead to unexpected errors at runtime.</p>
<p>With <code>strictNullChecks</code> set to true, <code>null</code> and <code>undefined</code> have their own types, and you'll get a type error if you assign them to a variable that expects a concrete value (for example, <code>string</code>).</p>
<pre><code class="lang-ts"><span class="hljs-keyword">let</span> whoSangThis: <span class="hljs-built_in">string</span> = getSong();

<span class="hljs-keyword">const</span> singles = [
  { song: <span class="hljs-string">'touch of grey'</span>, artist: <span class="hljs-string">'grateful dead'</span> },
  { song: <span class="hljs-string">'paint it black'</span>, artist: <span class="hljs-string">'rolling stones'</span> },
];

<span class="hljs-keyword">const</span> single = singles.find(<span class="hljs-function">(<span class="hljs-params">s</span>) =&gt;</span> s.song === whoSangThis);

<span class="hljs-built_in">console</span>.log(single.artist);
</code></pre>
<p>Above, <code>singles.find</code> has no guarantee that it will find the song – but we have written the code as though it always will.</p>
<p>By setting <code>strictNullChecks</code> to true, TypeScript will raise an error because we haven't made a guarantee that <code>single</code> exists before trying to use it:</p>
<pre><code class="lang-ts"><span class="hljs-keyword">const</span> getSong = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">return</span> <span class="hljs-string">'song'</span>;
};

<span class="hljs-keyword">let</span> whoSangThis: <span class="hljs-built_in">string</span> = getSong();

<span class="hljs-keyword">const</span> singles = [
  { song: <span class="hljs-string">'touch of grey'</span>, artist: <span class="hljs-string">'grateful dead'</span> },
  { song: <span class="hljs-string">'paint it black'</span>, artist: <span class="hljs-string">'rolling stones'</span> },
];

<span class="hljs-keyword">const</span> single = singles.find(<span class="hljs-function">(<span class="hljs-params">s</span>) =&gt;</span> s.song === whoSangThis);

<span class="hljs-built_in">console</span>.log(single.artist); <span class="hljs-comment">// ERROR: Object is possibly 'undefined'.</span>
</code></pre>
<p>TypeScript is basically telling us to ensure <code>single</code> exists before using it. We need to check if it isn't <code>null</code> or <code>undefined</code> first:</p>
<pre><code class="lang-ts"><span class="hljs-keyword">if</span> (single) {
  <span class="hljs-built_in">console</span>.log(single.artist); <span class="hljs-comment">// rolling stones</span>
}
</code></pre>
<h2 id="heading-narrowing-in-typescript">Narrowing in TypeScript</h2>
<p>In a TypeScript program, <strong>a variable can move from a less precise type to a more precise type.</strong> This process is called type narrowing.</p>
<p>Here's a simple example showing how TypeScript narrows down the less specific type of <code>string | number</code> to more specific types when we use if-statements with <code>typeof</code>:</p>
<pre><code class="lang-ts"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">addAnother</span>(<span class="hljs-params">val: <span class="hljs-built_in">string</span> | <span class="hljs-built_in">number</span></span>) </span>{
  <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> val === <span class="hljs-string">'string'</span>) {
    <span class="hljs-comment">// TypeScript treats `val` as a string in this block, so we can use string methods on `val` and TypeScript won't shout at us</span>
    <span class="hljs-keyword">return</span> val.concat(<span class="hljs-string">' '</span> + val);
  }

  <span class="hljs-comment">// TypeScript knows `val` is a number here</span>
  <span class="hljs-keyword">return</span> val + val;
}

<span class="hljs-built_in">console</span>.log(addAnother(<span class="hljs-string">'Woooo'</span>)); <span class="hljs-comment">// Woooo Woooo</span>
<span class="hljs-built_in">console</span>.log(addAnother(<span class="hljs-number">20</span>)); <span class="hljs-comment">// 40</span>
</code></pre>
<p>Another example: below, we have defined a union type called <code>allVehicles</code>, which can either be of type <code>Plane</code> or <code>Train</code>.</p>
<pre><code class="lang-ts"><span class="hljs-keyword">interface</span> Vehicle {
  topSpeed: <span class="hljs-built_in">number</span>;
}

<span class="hljs-keyword">interface</span> Train <span class="hljs-keyword">extends</span> Vehicle {
  carriages: <span class="hljs-built_in">number</span>;
}

<span class="hljs-keyword">interface</span> Plane <span class="hljs-keyword">extends</span> Vehicle {
  wingSpan: <span class="hljs-built_in">number</span>;
}

<span class="hljs-keyword">type</span> PlaneOrTrain = Plane | Train;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getSpeedRatio</span>(<span class="hljs-params">v: PlaneOrTrain</span>) </span>{
  <span class="hljs-comment">// In here, we want to return topSpeed/carriages, or topSpeed/wingSpan</span>
  <span class="hljs-built_in">console</span>.log(v.carriages); <span class="hljs-comment">// ERROR: 'carriages' doesn't exist on type 'Plane'</span>
}
</code></pre>
<p>Since the function <code>getSpeedRatio</code> is working with multiple types, we need a way of distinguishing whether <code>v</code> is a <code>Plane</code> or <code>Train</code>. We could do this by giving both types a common distinguishing property, with a literal string value:</p>
<pre><code class="lang-ts"><span class="hljs-comment">// All trains must now have a type property equal to 'Train'</span>
<span class="hljs-keyword">interface</span> Train <span class="hljs-keyword">extends</span> Vehicle {
  <span class="hljs-keyword">type</span>: <span class="hljs-string">'Train'</span>;
  carriages: <span class="hljs-built_in">number</span>;
}

<span class="hljs-comment">// All trains must now have a type property equal to 'Plane'</span>
<span class="hljs-keyword">interface</span> Plane <span class="hljs-keyword">extends</span> Vehicle {
  <span class="hljs-keyword">type</span>: <span class="hljs-string">'Plane'</span>;
  wingSpan: <span class="hljs-built_in">number</span>;
}

<span class="hljs-keyword">type</span> PlaneOrTrain = Plane | Train;
</code></pre>
<p>Now we, and TypeScript, can narrow down the type of <code>v</code>:</p>
<pre><code class="lang-ts"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getSpeedRatio</span>(<span class="hljs-params">v: PlaneOrTrain</span>) </span>{
  <span class="hljs-keyword">if</span> (v.type === <span class="hljs-string">'Train'</span>) {
    <span class="hljs-comment">// TypeScript now knows that `v` is definitely a `Train`. It has narrowed down the type from the less specific `Plane | Train` type, into the more specific `Train` type</span>
    <span class="hljs-keyword">return</span> v.topSpeed / v.carriages;
  }

  <span class="hljs-comment">// If it's not a Train, TypeScript narrows down that `v` must be a Plane - smart!</span>
  <span class="hljs-keyword">return</span> v.topSpeed / v.wingSpan;
}

<span class="hljs-keyword">let</span> bigTrain: Train = {
  <span class="hljs-keyword">type</span>: <span class="hljs-string">'Train'</span>,
  topSpeed: <span class="hljs-number">100</span>,
  carriages: <span class="hljs-number">20</span>,
};

<span class="hljs-built_in">console</span>.log(getSpeedRatio(bigTrain)); <span class="hljs-comment">// 5</span>
</code></pre>
<h2 id="heading-bonus-typescript-with-react">Bonus: TypeScript with React</h2>
<p>TypeScript has full support for React and JSX. This means we can use TypeScript with the three most common React frameworks: </p>
<ul>
<li>create-react-app (<a target="_blank" href="https://create-react-app.dev/docs/adding-typescript/">TS setup</a>)</li>
<li>Gatsby (<a target="_blank" href="https://www.gatsbyjs.com/docs/how-to/custom-configuration/typescript/">TS setup</a>)</li>
<li>Next.js (<a target="_blank" href="https://nextjs.org/learn/excel/typescript">TS setup</a>)</li>
</ul>
<p>If you require a more custom React-TypeScript configuration, you could setup <a target="_blank" href="https://webpack.js.org/">Webpack</a> (a module bundler) and configure the <code>tsconfig.json</code> yourself. But most of the time, a framework will do the job.</p>
<p>To setup up create-react-app with TypeScript, for example, simply run:</p>
<pre><code class="lang-ts">npx create-react-app my-app --template typescript

# or

yarn create react-app my-app --template typescript
</code></pre>
<p>In the src folder, we can now create files with <code>.ts</code> (for regular TypeScript files) or <code>.tsx</code> (for TypeScript with React) extensions and write our components with TypeScript. This will then compile down into JavaScript in the public folder.</p>
<h3 id="heading-react-props-with-typescript">React props with TypeScript</h3>
<p>Below, we are saying that <code>Person</code> should be a React functional component that accepts a props object with the props <code>name</code>, which should be a string, and <code>age</code>, which should be a number.</p>
<pre><code class="lang-tsx">// src/components/Person.tsx
import React from 'react';

const Person: React.FC&lt;{
  name: string;
  age: number;
}&gt; = ({ name, age }) =&gt; {
  return (
    &lt;div&gt;
      &lt;div&gt;{name}&lt;/div&gt;
      &lt;div&gt;{age}&lt;/div&gt;
    &lt;/div&gt;
  );
};

export default Person;
</code></pre>
<p>But most developers prefer to use an interface to specify prop types:</p>
<pre><code class="lang-tsx">interface Props {
  name: string;
  age: number;
}

const Person: React.FC&lt;Props&gt; = ({ name, age }) =&gt; {
  return (
    &lt;div&gt;
      &lt;div&gt;{name}&lt;/div&gt;
      &lt;div&gt;{age}&lt;/div&gt;
    &lt;/div&gt;
  );
};
</code></pre>
<p>We can then import this component into <code>App.tsx</code>. If we don't provide the necessary props, TypeScript will give an error.</p>
<pre><code class="lang-tsx">import React from 'react';
import Person from './components/Person';

const App: React.FC = () =&gt; {
  return (
    &lt;div&gt;
      &lt;Person name='John' age={48} /&gt;
    &lt;/div&gt;
  );
};

export default App;
</code></pre>
<p>Here are a few examples for what we could have as prop types:</p>
<pre><code class="lang-tsx">interface PersonInfo {
  name: string;
  age: number;
}

interface Props {
  text: string;
  id: number;
  isVeryNice?: boolean;
  func: (name: string) =&gt; string;
  personInfo: PersonInfo;
}
</code></pre>
<h3 id="heading-react-hooks-with-typescript">React hooks with TypeScript</h3>
<h4 id="heading-usestate">useState()</h4>
<p>We can declare what types a state variable should be by using angle brackets. Below, if we omitted the angle brackets, TypeScript would infer that <code>cash</code> is a number. So, if want to enable it to also be null, we have to specify:</p>
<pre><code class="lang-tsx">const Person: React.FC&lt;Props&gt; = ({ name, age }) =&gt; {
  const [cash, setCash] = useState&lt;number | null&gt;(1);

  setCash(null);

  return (
    &lt;div&gt;
      &lt;div&gt;{name}&lt;/div&gt;
      &lt;div&gt;{age}&lt;/div&gt;
    &lt;/div&gt;
  );
};
</code></pre>
<h4 id="heading-useref">useRef()</h4>
<p><code>useRef</code> returns a mutable object that persists for the lifetime of the component. We can tell TypeScript what the ref object should refer to – below we say the prop should be a <code>HTMLInputElement</code>:</p>
<pre><code class="lang-tsx">const Person: React.FC = () =&gt; {
  // Initialise .current property to null
  const inputRef = useRef&lt;HTMLInputElement&gt;(null);

  return (
    &lt;div&gt;
      &lt;input type='text' ref={inputRef} /&gt;
    &lt;/div&gt;
  );
};
</code></pre>
<p>For more information on React with TypeScript, checkout these <a target="_blank" href="https://react-typescript-cheatsheet.netlify.app/">awesome React-TypeScript cheatsheets</a>.</p>
<h2 id="heading-useful-resources-amp-further-reading">Useful resources &amp; further reading</h2>
<ul>
<li><a target="_blank" href="https://www.typescriptlang.org/docs/handbook/2/everyday-types.html">The official TypeScript docs</a></li>
<li><a target="_blank" href="https://www.youtube.com/watch?v=2pZmKW9-I_k&amp;list=PL4cUxeGkcC9gUgr39Q_yD6v-bSyMwKPUI&amp;ab_channel=TheNetNinja">The Net Ninja's TypeScript video series</a> (awesome!)</li>
<li><a target="_blank" href="https://www.youtube.com/watch?v=Z5iWr6Srsj8&amp;ab_channel=BenAwad">Ben Awad's TypeScript with React video</a></li>
<li><a target="_blank" href="https://www.typescriptlang.org/docs/handbook/2/narrowing.html">Narrowing in TypeScript</a> (a very interesting feature of TS that you should learn)</li>
<li><a target="_blank" href="https://www.typescriptlang.org/docs/handbook/2/functions.html#function-overloads">Function overloads</a></li>
<li><a target="_blank" href="https://developer.mozilla.org/en-US/docs/Glossary/Primitive">Primitive values in JavaScript</a></li>
<li><a target="_blank" href="https://www.w3schools.com/js/js_object_definition.asp">JavaScript objects</a></li>
</ul>
<h2 id="heading-thanks-for-reading">Thanks for reading!</h2>
<p>Hope that was useful. If you made it to here, you now know the main fundamentals of TypeScript and can start using it in your projects.</p>
<p>Again, you can also download my <a target="_blank" href="https://doabledanny.gumroad.com/l/typescript-cheat-sheet-pdf">one-page TypeScript cheat sheet PDF</a> or <a target="_blank" href="https://doabledanny.gumroad.com/l/typescript-cheat-sheet-poster">order a physical poster</a>.</p>
<p>For more from me, you can find me on <a target="_blank" href="https://mobile.twitter.com/doabledanny">Twitter</a> and <a target="_blank" href="https://www.youtube.com/channel/UC0URylW_U4i26wN231yRqvA">YouTube</a>.</p>
<p>Cheers!</p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
