<?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[ David Jaja - 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[ David Jaja - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Sun, 24 May 2026 16:29:50 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/author/Daiveed/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to Build a Reusable Keyboard Shortcut Listener Component in React ]]>
                </title>
                <description>
                    <![CDATA[ If you’re like me and you loveeeeee shortcuts, you know how satisfying it is to press a few keys and watch the magic happen. Whether it’s the familiar Ctrl+C – Ctrl+V that devs use to “borrow code” 😉 from LLMs and code pages, or the personalised sho... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-build-a-reusable-keyboard-shortcut-listener-component-in-react/</link>
                <guid isPermaLink="false">67606d5e81f45e690a86fe00</guid>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Accessibility ]]>
                    </category>
                
                    <category>
                        <![CDATA[ CSS ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ David Jaja ]]>
                </dc:creator>
                <pubDate>Mon, 16 Dec 2024 18:11:42 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1733895763796/17684457-fb85-48d4-b049-ddbaf0b5281e.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>If you’re like me and you loveeeeee shortcuts, you know how satisfying it is to press a few keys and watch the magic happen. Whether it’s the familiar Ctrl+C – Ctrl+V that devs use to “borrow code” 😉 from LLMs and code pages, or the personalised shortcuts we set up in our favourite tools, keyboard shortcuts save time and make us feel like a computer wiz.</p>
<p>Well, fear not! I’ve cracked the code for building components that trigger and respond to keyboard shortcuts. In this article, I’ll teach you how to create them with React, Tailwind CSS, and Framer Motion.</p>
<h2 id="heading-table-of-content">Table of Content</h2>
<p>Here’s everything we’ll cover:</p>
<ul>
<li><p><a class="post-section-overview" href="#heading-prerequisites">Prerequisites</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-is-a-keyboard-shortcut-listener-ksl-component">What Is a Keyboard Shortcut Listener (KSL) Component?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-build-the-ksl-component">How to Build the KSL Component</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-create-the-reveal-component">How to Create the Reveal Component</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-trigger-the-component-via-keyboard-shortcut">How to Trigger the Component via Keyboard Shortcut</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-animate-the-components-visibility">How to Animate the Component’s Visibility</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-optimize-your-ksl-component">How to Optimize Your KSL Component</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h2 id="heading-prerequisites">Prerequisites</h2>
<ul>
<li><p>Fundamentals of HTML, CSS, and Tailwind CSS</p>
</li>
<li><p>Fundamentals of JavaScript, React, and React Hooks.</p>
</li>
</ul>
<h2 id="heading-what-is-a-keyboard-shortcut-listener-ksl-component">What Is a Keyboard Shortcut Listener (KSL) Component?</h2>
<p>A <strong>Keyboard Shortcut Listener component (KSLC)</strong> is a component that listens for specific key combinations and triggers actions in your app. It's designed to make your app respond to keyboard shortcuts, allowing for a smoother, more efficient user experience.</p>
<h3 id="heading-why-is-it-important">Why is it important?</h3>
<ul>
<li><p><strong>Accessibility</strong>: The KSL component makes it simple for people who use a keyboard to trigger actions, making your app more inclusive and easy to use.</p>
</li>
<li><p><strong>Snappier Experience</strong>: Shortcuts are quick and efficient, allowing users to get things done in less time. No more fumbling around for the mouse—just hit a key (or two) and boom, action happens!</p>
</li>
<li><p><strong>Reusability</strong>: Once you’ve set up your KSL, it can handle different shortcuts across your app, making it easy to add without rewriting the same logic.</p>
</li>
<li><p><strong>Cleaner Code</strong>: Instead of scattering keyboard event listeners everywhere, the KSL component keeps things tidy by centralising the logic. Your code stays clean, organized, and easier to maintain.</p>
</li>
</ul>
<h2 id="heading-how-to-build-the-ksl-component">How to Build the KSL Component</h2>
<p>I've prepared a GitHub repository with <a target="_blank" href="https://github.com/Daiveedjay/KSL-Component/tree/starter">starter files</a> to speed things up. Simply clone this repo and install the dependencies.</p>
<p>For this project, we’re using Tailwind’s home page as our muse and creating the KSL functionality. After installing and running the build command, here’s what your page should look like:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1733861510569/fd94572d-e973-4637-ab65-9dd5e944065f.png" alt="fd94572d-e973-4637-ab65-9dd5e944065f" class="image--center mx-auto" width="1920" height="912" loading="lazy"></p>
<h2 id="heading-how-to-create-the-reveal-component">How to Create the Reveal Component</h2>
<p>The reveal component is the component we want to show when we use the shortcut.</p>
<p>To begin, create a file called <code>search-box.tsx</code> and paste in this code:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">SearchBox</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">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"fixed top-0 left-0 w-full h-full backdrop-blur-sm bg-slate-900/50 "</span>&gt;</span>
      {" "}
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">" p-[15vh] text-[#939AA7] h-full"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"max-w-xl mx-auto divide-y divide-[#939AA7] bg-[#1e293b] rounded-md"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"relative flex justify-between px-4 py-2 text-sm "</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex items-center w-full gap-2 text-white"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">BiSearch</span> <span class="hljs-attr">size</span>=<span class="hljs-string">{20}</span> /&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
                <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span>
                <span class="hljs-attr">className</span>=<span class="hljs-string">"w-full h-full p-2 bg-transparent focus-within:outline-none"</span>
                <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Search Documentation"</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> <span class="hljs-attr">className</span>=<span class="hljs-string">"absolute -translate-y-1/2 right-4 top-1/2 "</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">kbd</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"p-1 text-xs rounded-[4px] bg-[#475569] font-sans font-semibold text-slate-400"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">abbr</span> <span class="hljs-attr">title</span>=<span class="hljs-string">"Escape"</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"no-underline "</span>&gt;</span>
                  Esc{" "}
                <span class="hljs-tag">&lt;/<span class="hljs-name">abbr</span>&gt;</span>{" "}
              <span class="hljs-tag">&lt;/<span class="hljs-name">kbd</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 class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex items-center justify-center p-10 text-center "</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-xl"</span>&gt;</span>
              How many licks does it take to get to the center of a Tootsie pop?
            <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>
        <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 class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<p>Ok, so what’s happening in this code?</p>
<ol>
<li><p><strong>Main Overlay (</strong><code>&lt;div className="fixed top-0 left-0 ..."&gt;</code>)</p>
<ul>
<li><p>This is the full-screen overlay that dims the background.</p>
</li>
<li><p>The <code>backdrop-blur-sm</code> adds a subtle blur to the backdrop, and <code>bg-slate-900/50</code> gives it a semi-transparent dark overlay.</p>
</li>
</ul>
</li>
<li><p><strong>Search Box Wrapper (</strong><code>&lt;div className="p-[15vh] ..."&gt;</code>)</p>
<ul>
<li><p>The content is centered using padding and flex utilities.</p>
</li>
<li><p>The <code>max-w-xl</code> makes sure that the search box stays within a reasonable width for readability.</p>
</li>
</ul>
</li>
</ol>
<p>Then in your <code>App.tsx</code>, create a state that dynamically shows that component:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> [isOpen, setIsOpen] = useState&lt;boolean&gt;(<span class="hljs-literal">false</span>);
</code></pre>
<ul>
<li><p><code>useState</code>: This hook initializes <code>isOpen</code> to <code>false</code>, meaning the search box is hidden by default.</p>
</li>
<li><p>When <code>isOpen</code> is set to <code>true</code>, the <code>SearchBox</code> component will render on the screen.</p>
</li>
</ul>
<p>And render the search component:</p>
<pre><code class="lang-javascript">  {isOpen &amp;&amp; <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">SearchBox</span> /&gt;</span></span>}
</code></pre>
<p>To show the search component, add a toggle function to the input button:</p>
<pre><code class="lang-javascript">&lt;button
  type=<span class="hljs-string">"button"</span>
  className=<span class="hljs-string">"items-center hidden h-12 px-4 space-x-3 text-left rounded-lg shadow-sm sm:flex w-72 ring-slate-900/10 focus:outline-none hover:ring-2 hover:ring-sky-500 focus:ring-2 focus:ring-sky-500 bg-slate-800 ring-0 text-slate-300 highlight-white/5 hover:bg-slate-700"</span>
  onClick={<span class="hljs-function">() =&gt;</span> setIsOpen(<span class="hljs-literal">true</span>)}&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">BiSearch</span> <span class="hljs-attr">size</span>=<span class="hljs-string">{20}</span> /&gt;</span></span>
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex-auto"</span>&gt;</span>Quick search...<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span></span>
   <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">kbd</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"font-sans font-semibold text-slate-500"</span>&gt;</span>
   <span class="hljs-tag">&lt;<span class="hljs-name">abbr</span> <span class="hljs-attr">title</span>=<span class="hljs-string">"Control"</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"no-underline text-slate-500"</span>&gt;</span>
    Ctrl{" "}
    <span class="hljs-tag">&lt;/<span class="hljs-name">abbr</span>&gt;</span>{" "}
    K
   <span class="hljs-tag">&lt;/<span class="hljs-name">kbd</span>&gt;</span></span>
&lt;/button&gt;
</code></pre>
<p>The <code>onClick</code> event sets <code>isOpen</code> to <code>true</code>, displaying the <code>SearchBox</code>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1733861855356/87adf797-9378-4f2f-bae4-d1b45f6122d2.gif" alt="87adf797-9378-4f2f-bae4-d1b45f6122d2" class="image--center mx-auto" width="800" height="377" loading="lazy"></p>
<p>But as you’ve seen, this was triggered by a click action, not a keyboard shortcut action. Let’s do that next.</p>
<h2 id="heading-how-to-trigger-the-component-via-keyboard-shortcut">How to Trigger the Component via Keyboard Shortcut</h2>
<p>To make the reveal component open and close using a keyboard shortcut, we’ll use a <code>useEffect</code> hook to listen for specific key combinations and update the component’s state accordingly.</p>
<h3 id="heading-step-1-listen-for-keyboard-events">Step 1: Listen for Keyboard Events</h3>
<p>Add an <code>useEffect</code> hook in your <code>App.tsx</code> file to listen for key presses:</p>
<pre><code class="lang-javascript">  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> handleKeyDown = <span class="hljs-function">(<span class="hljs-params">event: KeyboardEvent</span>) =&gt;</span> {
      <span class="hljs-keyword">if</span> (event.ctrlKey &amp;&amp; event.key === Key.K) {
        event.preventDefault(); <span class="hljs-comment">// Prevent default browser behavior</span>

      }    };

    <span class="hljs-built_in">window</span>.addEventListener(<span class="hljs-string">"keydown"</span>, handleKeyDown);
    <span class="hljs-keyword">return</span> <span class="hljs-function">() =&gt;</span> {
      <span class="hljs-built_in">window</span>.removeEventListener(<span class="hljs-string">"keydown"</span>, handleKeyDown);
    };
  }, []);
</code></pre>
<p>What’s happening in this code?</p>
<ol>
<li><p><strong>Effect Setup (</strong><code>useEffect</code>)</p>
<ul>
<li><code>useEffect</code> ensures that the event listener for key presses is added when the component mounts and cleaned up when the component unmounts, preventing memory leaks.</li>
</ul>
</li>
<li><p><strong>Key Combination (</strong><code>event.ctrlKey &amp;&amp; event.key === "k"</code>)</p>
<ul>
<li><p>The <code>event.ctrlKey</code> checks if the <strong>Control</strong> key is being pressed.</p>
</li>
<li><p>The <code>event.key === "k"</code> ensures we’re listening specifically for the "K" key. Together, this checks if the <strong>Ctrl + K</strong> combination is pressed.</p>
</li>
</ul>
</li>
<li><p><strong>Prevent Default Behavior (</strong><code>event.preventDefault()</code>)</p>
<ul>
<li>Some browsers may have default behaviors tied to key combinations like <strong>Ctrl + K</strong> (e.g., focusing the browser’s address bar). Calling <code>preventDefault</code> stops this behavior.</li>
</ul>
</li>
<li><p><strong>Event Cleanup (</strong><code>return () =&gt; ...</code>)</p>
<ul>
<li>The cleanup function removes the event listener to prevent duplicate listeners from being added if the component re-renders.</li>
</ul>
</li>
</ol>
<h3 id="heading-step-2-toggle-component-visibility">Step 2: Toggle Component Visibility</h3>
<p>Next, update the <code>handleKeyDown</code> function to toggle the <code>SearchBox</code> visibility when the shortcut is pressed:</p>
<pre><code class="lang-javascript">useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> handleKeyDown = <span class="hljs-function">(<span class="hljs-params">event: KeyboardEvent</span>) =&gt;</span> {
      <span class="hljs-comment">// Listen for Ctrl + K</span>
      <span class="hljs-keyword">if</span> (event.ctrlKey &amp;&amp; event.key === Key.K) {
        event.preventDefault(); <span class="hljs-comment">// Prevent default browser behavior</span>
        setIsOpen(<span class="hljs-function">(<span class="hljs-params">prev</span>) =&gt;</span> !prev); <span class="hljs-comment">// Toggle the search box</span>
      } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (event.key === Key.Escape) {
        setIsOpen(<span class="hljs-literal">false</span>); <span class="hljs-comment">// Close the search box</span>
      }
    };

    <span class="hljs-built_in">window</span>.addEventListener(<span class="hljs-string">"keydown"</span>, handleKeyDown);
    <span class="hljs-keyword">return</span> <span class="hljs-function">() =&gt;</span> {
      <span class="hljs-built_in">window</span>.removeEventListener(<span class="hljs-string">"keydown"</span>, handleKeyDown);
    };
  }, []);
</code></pre>
<p>What’s happening in this code?</p>
<ol>
<li><p><strong>Toggling State</strong> (<code>setIsOpen((prev) =&gt; !prev)</code>)</p>
<ul>
<li><p>When <strong>Ctrl + K</strong> is pressed, the <code>setIsOpen</code> state setter toggles the visibility of the <code>SearchBox</code>.</p>
</li>
<li><p>The <code>prev</code> argument represents the previous state. Using <code>!prev</code> flips its value:</p>
<ul>
<li><p><code>true</code> (open) becomes <code>false</code> (close).</p>
</li>
<li><p><code>false</code> (closed) becomes <code>true</code> (open).</p>
</li>
</ul>
</li>
</ul>
</li>
<li><p><strong>Closing with the Escape Key (</strong><code>event.key === "Escape"</code>)</p>
<ul>
<li>When the <strong>Escape</strong> key is pressed, <code>setIsOpen(false)</code> explicitly sets the state to <code>false</code>, closing the <code>SearchBox</code>.</li>
</ul>
</li>
</ol>
<p>This results in the following:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1733861983226/9c6ff7ef-a067-42c9-b6c7-afd35955731e.gif" alt="9c6ff7ef-a067-42c9-b6c7-afd35955731e" class="image--center mx-auto" width="800" height="367" loading="lazy"></p>
<h2 id="heading-how-to-animate-the-components-visibility">How to Animate the Component’s Visibility</h2>
<p>At the moment, our component works, but it lacks a little flair, wouldn’t you say? Let’s change that.</p>
<h3 id="heading-step-1-create-the-overlay-component">Step 1: Create the Overlay Component</h3>
<p>We’ll start by creating an <strong>overlay component</strong>, which acts as the dark, blurred backdrop for the search box. Here’s the base version:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { ReactNode } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">OverlayWrapper</span>(<span class="hljs-params">{ children }: { children: ReactNode }</span>) </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">"fixed top-0 left-0 w-full h-full backdrop-blur-sm bg-slate-900/50 "</span>&gt;</span>
      {children}
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<h3 id="heading-step-2-add-animations-to-the-overlay">Step 2: Add Animations to the Overlay</h3>
<p>Now, let’s make the overlay fade in and out using Framer Motion. Update the <code>OverlayWrapper</code> component like this:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { motion } <span class="hljs-keyword">from</span> <span class="hljs-string">"framer-motion"</span>;
<span class="hljs-keyword">import</span> { ReactNode } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">OverlayWrapper</span>(<span class="hljs-params">{ children }: { children: ReactNode }</span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">motion.div</span>
      <span class="hljs-attr">initial</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">opacity:</span> <span class="hljs-attr">0</span> }}
      <span class="hljs-attr">animate</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">opacity:</span> <span class="hljs-attr">1</span> }}
      <span class="hljs-attr">exit</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">opacity:</span> <span class="hljs-attr">0</span> }}
      <span class="hljs-attr">className</span>=<span class="hljs-string">"fixed top-0 left-0 w-full h-full backdrop-blur-sm bg-slate-900/50 "</span>&gt;</span>
      {children}
    <span class="hljs-tag">&lt;/<span class="hljs-name">motion.div</span>&gt;</span></span>
  );
}
</code></pre>
<h5 id="heading-key-animation-props">Key animation props:</h5>
<ul>
<li><p><code>initial</code>: Sets the starting state when the component is mounted (fully transparent).</p>
</li>
<li><p><code>animate</code>: Defines the state to animate toward (fully opaque).</p>
</li>
<li><p><code>exit</code>: Specifies the animation when the component is unmounted (fading out).</p>
</li>
</ul>
<h3 id="heading-step-3-animate-the-search-box">Step 3: Animate the Search Box</h3>
<p>Next, add some motion to the search box itself. We’ll make it slide and fade in when it appears and slide out when it disappears.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { motion } <span class="hljs-keyword">from</span> <span class="hljs-string">"framer-motion"</span>;
<span class="hljs-keyword">import</span> { BiSearch } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-icons/bi"</span>;
<span class="hljs-keyword">import</span> OverlayWrapper <span class="hljs-keyword">from</span> <span class="hljs-string">"./overlay"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">SearchBox</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">OverlayWrapper</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">motion.div</span>
        <span class="hljs-attr">initial</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">y:</span> "<span class="hljs-attr">-10</span>%", <span class="hljs-attr">opacity:</span> <span class="hljs-attr">0</span> }}
        <span class="hljs-attr">animate</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">y:</span> "<span class="hljs-attr">0</span>%", <span class="hljs-attr">opacity:</span> <span class="hljs-attr">1</span> }}
        <span class="hljs-attr">exit</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">y:</span> "<span class="hljs-attr">-5</span>%", <span class="hljs-attr">opacity:</span> <span class="hljs-attr">0</span> }}
        <span class="hljs-attr">className</span>=<span class="hljs-string">" p-[15vh] text-[#939AA7] h-full"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span>
          <span class="hljs-attr">className</span>=<span class="hljs-string">"max-w-xl mx-auto divide-y divide-[#939AA7] bg-[#1e293b] rounded-md"</span>
        &gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"relative flex justify-between px-4 py-2 text-sm "</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex items-center w-full gap-2 text-white"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">BiSearch</span> <span class="hljs-attr">size</span>=<span class="hljs-string">{20}</span> /&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
                <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span>
                <span class="hljs-attr">className</span>=<span class="hljs-string">"w-full h-full p-2 bg-transparent focus-within:outline-none"</span>
                <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Search Documentation"</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> <span class="hljs-attr">className</span>=<span class="hljs-string">"absolute -translate-y-1/2 right-4 top-1/2 "</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">kbd</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"p-1 text-xs rounded-[4px] bg-[#475569] font-sans font-semibold text-slate-400"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">abbr</span> <span class="hljs-attr">title</span>=<span class="hljs-string">"Escape"</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"no-underline "</span>&gt;</span>
                  Esc{" "}
                <span class="hljs-tag">&lt;/<span class="hljs-name">abbr</span>&gt;</span>{" "}
              <span class="hljs-tag">&lt;/<span class="hljs-name">kbd</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 class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex items-center justify-center p-10 text-center "</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-xl"</span>&gt;</span>
              How many licks does it take to get to the center of a Tootsie pop?
            <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>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">motion.div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">OverlayWrapper</span>&gt;</span></span>
  );
}
</code></pre>
<h3 id="heading-step-4-enable-animation-tracking-with-animatepresence">Step 4: Enable Animation Tracking with <code>AnimatePresence</code></h3>
<p>Finally, wrap your conditional rendering logic in the <code>AnimatePresence</code> component provided by <strong>Framer Motion</strong>. This ensures Framer Motion tracks when elements enter and leave the DOM.</p>
<pre><code class="lang-javascript">&lt;AnimatePresence&gt;{isOpen &amp;&amp; <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">SearchBox</span> /&gt;</span></span>}&lt;/AnimatePresence&gt;
</code></pre>
<p>This enables Framer Motion to track when an element enters and leaves the DOM. With this, we get the following result:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1733862299745/e4c9858c-d10a-4817-bf41-697fa103d096.gif" alt="e4c9858c-d10a-4817-bf41-697fa103d096" class="image--center mx-auto" width="777" height="345" loading="lazy"></p>
<p>Ah, much better!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1733862351332/a1888e83-8df6-45cc-80c4-db1e2e8e7025.gif" alt="a1888e83-8df6-45cc-80c4-db1e2e8e7025" class="image--center mx-auto" width="498" height="498" loading="lazy"></p>
<h2 id="heading-how-to-optimize-your-ksl-component">How to Optimize Your KSL Component</h2>
<p>If you thought we were done, not so fast…We still have a little more to do.</p>
<p>We need to optimize for accessibility. We should add a way for users to close the search component with a mouse, as accessibility is very important.</p>
<p>To do this, start by creating a hook called <code>useClickOutside</code>. This hook uses a reference element to know when a user is clicking outside the target element (search box) which is a very popular behaviour for closing modals and KSLCs.</p>
<pre><code class="lang-javascript">
<span class="hljs-keyword">import</span> { useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

type ClickOutsideHandler = <span class="hljs-function">(<span class="hljs-params">event: Event</span>) =&gt;</span> <span class="hljs-keyword">void</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> useClickOutside = <span class="hljs-function">(<span class="hljs-params">
  ref: React.RefObject&lt;HTMLElement&gt;,
  handler: ClickOutsideHandler
</span>) =&gt;</span> {
  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> listener = <span class="hljs-function">(<span class="hljs-params">event: Event</span>) =&gt;</span> {
      <span class="hljs-comment">// Do nothing if clicking ref's element or descendant elements</span>
      <span class="hljs-keyword">if</span> (!ref.current || ref.current.contains(event.target <span class="hljs-keyword">as</span> Node)) <span class="hljs-keyword">return</span>;

      handler(event);
    };

    <span class="hljs-built_in">document</span>.addEventListener(<span class="hljs-string">"mousedown"</span>, listener);
    <span class="hljs-built_in">document</span>.addEventListener(<span class="hljs-string">"touchstart"</span>, listener);

    <span class="hljs-keyword">return</span> <span class="hljs-function">() =&gt;</span> {
      <span class="hljs-built_in">document</span>.removeEventListener(<span class="hljs-string">"mousedown"</span>, listener);
      <span class="hljs-built_in">document</span>.removeEventListener(<span class="hljs-string">"touchstart"</span>, listener);
    };
  }, [ref, handler]);
};
</code></pre>
<p>To use this hook, pass in the function responsible for opening and closing the search component:</p>
<pre><code class="lang-javascript">&lt;AnimatePresence&gt; {isOpen &amp;&amp; <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">SearchBox</span> <span class="hljs-attr">close</span>=<span class="hljs-string">{setIsOpen}</span> /&gt;</span></span>} &lt;/AnimatePresence&gt;
</code></pre>
<p>Then receive the function in the search with its proper prop type:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">SearchBox</span>(<span class="hljs-params">{
  close,
}: {
  close: React.Dispatch&lt;React.SetStateAction&lt;boolean&gt;&gt;;
}</span>) </span>{
</code></pre>
<p>After that, create a reference (ref) to the item you want to track and mark that element:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { motion } <span class="hljs-keyword">from</span> <span class="hljs-string">"framer-motion"</span>;
<span class="hljs-keyword">import</span> { useRef } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { BiSearch } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-icons/bi"</span>;
<span class="hljs-keyword">import</span> { useClickOutside } <span class="hljs-keyword">from</span> <span class="hljs-string">"../hooks/useClickOutside"</span>;
<span class="hljs-keyword">import</span> OverlayWrapper <span class="hljs-keyword">from</span> <span class="hljs-string">"./overlay"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">SearchBox</span>(<span class="hljs-params">{
  close,
}: {
  close: React.Dispatch&lt;React.SetStateAction&lt;boolean&gt;&gt;;
}</span>) </span>{
  <span class="hljs-keyword">const</span> searchboxRef = useRef&lt;HTMLDivElement&gt;(<span class="hljs-literal">null</span>);
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">OverlayWrapper</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">motion.div</span>
        <span class="hljs-attr">initial</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">y:</span> "<span class="hljs-attr">-10</span>%", <span class="hljs-attr">opacity:</span> <span class="hljs-attr">0</span> }}
        <span class="hljs-attr">animate</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">y:</span> "<span class="hljs-attr">0</span>%", <span class="hljs-attr">opacity:</span> <span class="hljs-attr">1</span> }}
        <span class="hljs-attr">exit</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">y:</span> "<span class="hljs-attr">-5</span>%", <span class="hljs-attr">opacity:</span> <span class="hljs-attr">0</span> }}
        <span class="hljs-attr">className</span>=<span class="hljs-string">" p-[15vh] text-[#939AA7] h-full"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span>
          <span class="hljs-attr">className</span>=<span class="hljs-string">"max-w-xl mx-auto divide-y divide-[#939AA7] bg-[#1e293b] rounded-md"</span>
          <span class="hljs-attr">ref</span>=<span class="hljs-string">{searchboxRef}</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"relative flex justify-between px-4 py-2 text-sm "</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex items-center w-full gap-2 text-white"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">BiSearch</span> <span class="hljs-attr">size</span>=<span class="hljs-string">{20}</span> /&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
                <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span>
                <span class="hljs-attr">className</span>=<span class="hljs-string">"w-full h-full p-2 bg-transparent focus-within:outline-none"</span>
                <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Search Documentation"</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> <span class="hljs-attr">className</span>=<span class="hljs-string">"absolute -translate-y-1/2 right-4 top-1/2 "</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">kbd</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"p-1 text-xs rounded-[4px] bg-[#475569] font-sans font-semibold text-slate-400"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">abbr</span> <span class="hljs-attr">title</span>=<span class="hljs-string">"Escape"</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"no-underline "</span>&gt;</span>
                  Esc{" "}
                <span class="hljs-tag">&lt;/<span class="hljs-name">abbr</span>&gt;</span>{" "}
              <span class="hljs-tag">&lt;/<span class="hljs-name">kbd</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 class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex items-center justify-center p-10 text-center "</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-xl"</span>&gt;</span>
              How many licks does it take to get to the center of a Tootsie pop?
            <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>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">motion.div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">OverlayWrapper</span>&gt;</span></span>
  );
}
</code></pre>
<p>Then pass in that ref and the function to be called when a click outside that element is detected.</p>
<pre><code class="lang-javascript">useClickOutside(searchboxRef, <span class="hljs-function">() =&gt;</span> close(<span class="hljs-literal">false</span>));
</code></pre>
<p>Testing it out now gives the following result:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1733862607091/5c77d8e0-6ba8-4c04-8d7d-c0d0d8f7c408.gif" alt="5c77d8e0-6ba8-4c04-8d7d-c0d0d8f7c408" class="image--center mx-auto" width="800" height="378" loading="lazy"></p>
<p>We can also optimize the code a bit more. Like we did with the accessibility feature, we can make out listener for detecting shortcuts much cleaner and efficient with the following steps.</p>
<p>First, create a <code>useKeyBindings</code> hook file for handling key press combinations.</p>
<p>Then define the hook and the Interface. The hook will accept an array of bindings, where each binding consists of:</p>
<ul>
<li><p>A <code>keys</code> array, which specifies the key combination (for example, ["Control", "k"])</p>
</li>
<li><p>A callback function, which gets called when the corresponding keys are pressed.</p>
</li>
</ul>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-comment">// Define the structure of a keybinding</span>
interface KeyBinding {
  <span class="hljs-attr">keys</span>: string[]; <span class="hljs-comment">// Array of keys (e.g., ["Control", "k"])</span>
  callback: <span class="hljs-function">() =&gt;</span> <span class="hljs-keyword">void</span>; <span class="hljs-comment">// Function to execute when the keys are pressed</span>
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> useKeyBindings = <span class="hljs-function">(<span class="hljs-params">bindings: KeyBinding[]</span>) =&gt;</span> {

};
</code></pre>
<p>Next, create the <code>handleKeyDown</code> function. Inside the hook, define a function that will listen for keyboard events. This function will check if the pressed keys match any defined key combinations.</p>
<p>We'll normalize the keys to lowercase so that the comparison is case-insensitive and track which keys are pressed by checking for <code>ctrlKey</code>, <code>shiftKey</code>, <code>altKey</code>, <code>metaKey</code>, and the key pressed (for example, "k" for Ctrl + K).</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> handleKeyDown = <span class="hljs-function">(<span class="hljs-params">event: KeyboardEvent</span>) =&gt;</span> {
  <span class="hljs-comment">// Track the keys that are pressed</span>
  <span class="hljs-keyword">const</span> pressedKeys = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Set</span>&lt;string&gt;();

  <span class="hljs-comment">// Check for modifier keys (Ctrl, Shift, Alt, Meta)</span>
  <span class="hljs-keyword">if</span> (event.ctrlKey) pressedKeys.add(<span class="hljs-string">"control"</span>);
  <span class="hljs-keyword">if</span> (event.shiftKey) pressedKeys.add(<span class="hljs-string">"shift"</span>);
  <span class="hljs-keyword">if</span> (event.altKey) pressedKeys.add(<span class="hljs-string">"alt"</span>);
  <span class="hljs-keyword">if</span> (event.metaKey) pressedKeys.add(<span class="hljs-string">"meta"</span>);

  <span class="hljs-comment">// Add the key that was pressed (e.g., "k" for Ctrl + K)</span>
  <span class="hljs-keyword">if</span> (event.key) pressedKeys.add(event.key.toLowerCase());
};
</code></pre>
<p>Next, we’ll compare the pressed keys with the keys array from our bindings to check if they match. If they do, we’ll call the associated callback function. We also ensure that the number of pressed keys matches the number of keys defined in the binding.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Loop through each keybinding</span>
bindings.forEach(<span class="hljs-function">(<span class="hljs-params">{ keys, callback }</span>) =&gt;</span> {
  <span class="hljs-comment">// Normalize the keys to lowercase for comparison</span>
  <span class="hljs-keyword">const</span> normalizedKeys = keys.map(<span class="hljs-function">(<span class="hljs-params">key</span>) =&gt;</span> key.toLowerCase());

  <span class="hljs-comment">// Check if the pressed keys match the keybinding</span>
  <span class="hljs-keyword">const</span> isMatch =
    pressedKeys.size === normalizedKeys.length &amp;&amp;
    normalizedKeys.every(<span class="hljs-function">(<span class="hljs-params">key</span>) =&gt;</span> pressedKeys.has(key));

  <span class="hljs-comment">// If the keys match, call the callback</span>
  <span class="hljs-keyword">if</span> (isMatch) {
    event.preventDefault(); <span class="hljs-comment">// Prevent default browser behavior</span>
    callback(); <span class="hljs-comment">// Execute the callback function</span>
  }
});
</code></pre>
<p>Finally, set up event listeners on the window object to listen for keydown events. These listeners will trigger the <code>handleKeyDown</code> function whenever a key is pressed. Make sure to add clean up the event listeners when the component unmounts.</p>
<pre><code class="lang-javascript">useEffect(<span class="hljs-function">() =&gt;</span> {
  <span class="hljs-comment">// Add event listeners for keydown</span>
  <span class="hljs-built_in">window</span>.addEventListener(<span class="hljs-string">"keydown"</span>, handleKeyDown);

  <span class="hljs-comment">// Cleanup the event listeners when the component unmounts</span>
  <span class="hljs-keyword">return</span> <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-built_in">window</span>.removeEventListener(<span class="hljs-string">"keydown"</span>, handleKeyDown);
  };
}, [bindings]);
</code></pre>
<p>The full <code>useKeyBindings</code> hook now put together looks like this:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

interface KeyBinding {
  <span class="hljs-attr">keys</span>: string[]; <span class="hljs-comment">// A combination of keys to trigger the callback (e.g., ["Control", "k"])</span>
  callback: <span class="hljs-function">() =&gt;</span> <span class="hljs-keyword">void</span>; <span class="hljs-comment">// The function to execute when the keys are pressed</span>
}

<span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">useKeyBindings</span>(<span class="hljs-params">bindings: KeyBinding[]</span>) </span>{
  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> handleKeyDown = <span class="hljs-function">(<span class="hljs-params">event: KeyboardEvent</span>) =&gt;</span> {
      bindings.forEach(<span class="hljs-function">(<span class="hljs-params">{ keys, callback }</span>) =&gt;</span> {
        <span class="hljs-keyword">const</span> normalizedKeys = keys.map(<span class="hljs-function">(<span class="hljs-params">key</span>) =&gt;</span> key.toLowerCase());
        <span class="hljs-keyword">const</span> pressedKeys = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Set</span>&lt;string&gt;();

        <span class="hljs-comment">// Track modifier keys explicitly</span>
        <span class="hljs-keyword">if</span> (event.ctrlKey) pressedKeys.add(<span class="hljs-string">"control"</span>);
        <span class="hljs-keyword">if</span> (event.shiftKey) pressedKeys.add(<span class="hljs-string">"shift"</span>);
        <span class="hljs-keyword">if</span> (event.altKey) pressedKeys.add(<span class="hljs-string">"alt"</span>);
        <span class="hljs-keyword">if</span> (event.metaKey) pressedKeys.add(<span class="hljs-string">"meta"</span>);

        <span class="hljs-comment">// Add the actual key pressed</span>
        <span class="hljs-keyword">if</span> (event.key) pressedKeys.add(event.key.toLowerCase());

        <span class="hljs-comment">// Match exactly: pressed keys must match the defined keys</span>
        <span class="hljs-keyword">const</span> isExactMatch =
          pressedKeys.size === normalizedKeys.length &amp;&amp;
          normalizedKeys.every(<span class="hljs-function">(<span class="hljs-params">key</span>) =&gt;</span> pressedKeys.has(key));

        <span class="hljs-keyword">if</span> (isExactMatch) {
          event.preventDefault(); <span class="hljs-comment">// Prevent default behavior</span>
          callback(); <span class="hljs-comment">// Execute the callback</span>
        }
      });
    };

    <span class="hljs-built_in">window</span>.addEventListener(<span class="hljs-string">"keydown"</span>, handleKeyDown);
    <span class="hljs-keyword">return</span> <span class="hljs-function">() =&gt;</span> {
      <span class="hljs-built_in">window</span>.removeEventListener(<span class="hljs-string">"keydown"</span>, handleKeyDown);
    };
  }, [bindings]);
}
</code></pre>
<p>Here’s how you can use this hook in your <code>App</code>:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { useKeyBindings } <span class="hljs-keyword">from</span> <span class="hljs-string">"./hooks/useKeyBindings"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</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> [isOpen, setIsOpen] = useState&lt;boolean&gt;(<span class="hljs-literal">false</span>);

  useKeyBindings([
    {
      <span class="hljs-attr">keys</span>: [<span class="hljs-string">"Control"</span>, <span class="hljs-string">"k"</span>], <span class="hljs-comment">// Listen for "Ctrl + K"</span>
      <span class="hljs-attr">callback</span>: <span class="hljs-function">() =&gt;</span> setIsOpen(<span class="hljs-function">(<span class="hljs-params">prev</span>) =&gt;</span> !prev), <span class="hljs-comment">// Toggle the search box</span>
    },
    {
      <span class="hljs-attr">keys</span>: [<span class="hljs-string">"Escape"</span>], <span class="hljs-comment">// Listen for "Escape"</span>
      <span class="hljs-attr">callback</span>: <span class="hljs-function">() =&gt;</span> setIsOpen(<span class="hljs-literal">false</span>), <span class="hljs-comment">// Close the search box</span>
    },
  ]);
</code></pre>
<p>Which gives the following result:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1733863013736/620e7362-33fa-45d3-b2e0-4c8afc873cfd.gif" alt="620e7362-33fa-45d3-b2e0-4c8afc873cfd" class="image--center mx-auto" width="800" height="373" loading="lazy"></p>
<p>With this approach, you can even add multiple shortcuts to trigger the search component’s visibility.</p>
<pre><code class="lang-javascript">useKeyBindings([
    {
      <span class="hljs-attr">keys</span>: [<span class="hljs-string">"Control"</span>, <span class="hljs-string">"k"</span>], <span class="hljs-comment">// Listen for "Ctrl + K"</span>
      <span class="hljs-attr">callback</span>: <span class="hljs-function">() =&gt;</span> setIsOpen(<span class="hljs-function">(<span class="hljs-params">prev</span>) =&gt;</span> !prev), <span class="hljs-comment">// Toggle the search box</span>
    },
    {
      <span class="hljs-attr">keys</span>: [<span class="hljs-string">"Control"</span>, <span class="hljs-string">"d"</span>], <span class="hljs-comment">// Listen for "Ctrl + D"</span>
      <span class="hljs-attr">callback</span>: <span class="hljs-function">() =&gt;</span> setIsOpen(<span class="hljs-function">(<span class="hljs-params">prev</span>) =&gt;</span> !prev), <span class="hljs-comment">// Toggle the search box</span>
    },
    {
      <span class="hljs-attr">keys</span>: [<span class="hljs-string">"Escape"</span>], <span class="hljs-comment">// Listen for "Escape"</span>
      <span class="hljs-attr">callback</span>: <span class="hljs-function">() =&gt;</span> setIsOpen(<span class="hljs-literal">false</span>), <span class="hljs-comment">// Close the search box</span>
    },
  ]);
</code></pre>
<p>Here are links to all the resources you may need for this article:</p>
<ul>
<li><p><a target="_blank" href="https://github.com/Daiveedjay/KSL-Component/tree/starter">Starter files</a></p>
</li>
<li><p><a target="_blank" href="https://github.com/Daiveedjay/KSL-Component/tree/main">Final</a></p>
</li>
</ul>
<h2 id="heading-conclusion">Conclusion</h2>
<p>I hope this article felt like a well-timed shortcut, getting you to the heart of building reusable keyboard shortcut components. With every keypress and animation, you can now turn ordinary web experiences extraordinary ones.</p>
<p>I hope your shortcuts help you create apps that click with your users. After all, the best journeys often start with just the right combination.</p>
<h3 id="heading-like-my-articles">Like my articles?</h3>
<p>Feel free to <a target="_blank" href="https://www.buymeacoffee.com/JajaDavid">buy me a coffee here</a>, to keep my brain chugging and provide more articles like this.</p>
<p><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXdVWaSayW-ZONciTLakWFfSKvOKoaQR3MTpyGmLR77hl58lDorTCRNfOZfP-dMf-2WcIwfSWZE_psVHr-4qU1CIy28hsLj755zJdEcsLp3blw6l1Wtu4EUxTZ8mSF--dCk6mEQRWg?key=ypBQIzv1TD8iWEKblpAC4CZM" alt="coffee-tom" width="620" height="461" loading="lazy"></p>
<h3 id="heading-contact-information">Contact Information</h3>
<p>Want to connect or contact me? Feel free to hit me up on the following:</p>
<ul>
<li><p>Twitter / X: <a target="_blank" href="https://twitter.com/JajaDavid8">@jajadavid8</a></p>
</li>
<li><p>LinkedIn: <a target="_blank" href="https://www.linkedin.com/in/david-jaja-8084251b4/">David Jaja</a></p>
</li>
<li><p>Email: <a target="_blank" href="http://Jajadavidjid@gmail.com">Jajadavidjid@gmail.com</a></p>
</li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Use WebCurate to Discover Helpful Developer Tools ]]>
                </title>
                <description>
                    <![CDATA[ Building Kreed, my collaborative project management tool, was no easy feat. But it did offer one perk: an endless stream of stress-induced caffeine highs. I don’t have a dedicated team, so I was juggling everything from design and deployment to marke... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-use-webcurate-to-discover-helpful-developer-tools/</link>
                <guid isPermaLink="false">672e31c2d0e4fe6467edeb83</guid>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Developer Tools ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Productivity ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ David Jaja ]]>
                </dc:creator>
                <pubDate>Fri, 08 Nov 2024 15:44:02 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1730908679140/f7c2ff53-9d06-4b2f-ae08-baaf219cba1f.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Building Kreed, my collaborative project management tool, was no easy feat. But it did offer one perk: an endless stream of stress-induced caffeine highs. I don’t have a dedicated team, so I was juggling everything from design and deployment to marketing and even user testing (because it’s not okay to test on production users—bummer 😂). </p>
<p>After quite a journey of trial and error, I found WebCurate, a platform that felt like the instruction manual I’d been missing. </p>
<p>In this article, I’ll take you through how WebCurate helped me simplify my journey with Kreed and share tips on discovering the best tools for your projects.</p>
<h2 id="heading-what-well-cover">What We’ll Cover</h2>
<ul>
<li><p><strong>What is WebCurate?:</strong> An overview of WebCurate’s platform </p>
</li>
<li><p><strong>How WebCurate Works:</strong> A look at WebCurate's curated categories to streamline your workflow.</p>
</li>
<li><p><strong>Finding the Right Tools:</strong> Tips for searching, filtering, and using WebCurate’s curated recommendations.</p>
</li>
<li><p><strong>Making the Most of WebCurate:</strong> Advice on leveraging the platform for your specific needs, with an example of finding a relevant tool.</p>
</li>
<li><p><strong>Essential Tools Discovered on WebCurate:</strong> A look at the essential tools WebCurate helped me discover for Kreed’s development and how they might help you.</p>
</li>
</ul>
<h2 id="heading-what-is-webcurate">What is WebCurate?</h2>
<p><a target="_blank" href="https://webcurate.co/">WebCurate</a> is a free platform designed to help developers, startups, and tech enthusiasts find high-value tools without the overwhelm.</p>
<p>Unlike other resources that flood you with endless options, WebCurate handpicks practical, relevant tools and resources tailored for productivity and development.</p>
<p><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXfUJtsMJ05qDT9ZcF9OG6xEDHFNFa2RBBG2fHmmxoftZStQuEwGOoZFkUVDdIBZUeXCLAqLCgkJ8oz2EQavBnSS8XLiUXPauzaYguT9HNJnpzvi-G6cFZhvormbptwXOohoRkOZ?key=PqN_g0HdcyYepwEb5e7OGQCR" alt="WebCurate's interface" width="1339" height="754" loading="lazy"></p>
<p>What makes WebCurate unique is its comprehensive scope. It offers a curated range of design tools and inspiration, developer tools, API integrations, debugging utilities, productivity aids, and even insights into industry trends.</p>
<p>Each resource on WebCurate is chosen for its ability to genuinely enhance workflow and project outcomes, so you spend less time searching and more time building.</p>
<h2 id="heading-how-webcurate-works">How WebCurate Works</h2>
<p>WebCurate provides resources across essential categories, like design assets, developer tools, and productivity guides. Think of it like a “greatest hits” album but for tools.</p>
<p>The platform features resources that span several essential areas:</p>
<ul>
<li><strong>Design Assets</strong>: From UI kits to icons and templates, WebCurate provides carefully selected design resources that can help developers and designers keep their projects on track without feeling lost in a sea of options.</li>
</ul>
<p><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXeudKwe93_l9Syfw2oHmR9bzBC1H4ThH0WhH3Jo74UY4I_rDqA1venrKd2ZRNgz3d9IHUrHSrXwGmj0kNdlBHv291WH0Dfk_sbyylj9NE3VrWUeHujzuldUUvJd1hZ5aQtbAH-KNQ?key=PqN_g0HdcyYepwEb5e7OGQCR" alt="Screenshot showing the Best Design Tools section" width="1600" height="760" loading="lazy"></p>
<ul>
<li><strong>Developer Tools</strong>: This includes everything from code libraries to APIs and frameworks that can speed up development workflows. Tools like these are sorted into categories to ensure you find the best fit for your tech stack.</li>
</ul>
<p><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXdCZ4HK8KR31C2-1hOAb0nj1Wu3FrSCN5QiH9A_kNDagmowpNHWdTxAdBHXNKb-E-v8T_4B8aCCPXTchJenfOab6-SajbfO1Il_DcFeetBmS0nWxLWbSTz_gM-W_M3CIJy1Mqbmtw?key=PqN_g0HdcyYepwEb5e7OGQCR" alt="Screenshot showing the Best Developer Tools section" width="1600" height="760" loading="lazy"></p>
<ul>
<li><strong>Industry Guides</strong>: WebCurate also offers practical guides tools, insights, and case studies to help developers stay ahead of industry trends and optimize their strategies.</li>
</ul>
<p><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXeeQ5sWhrBGm3mkNLECtks9cHVG0nbKBLTnJ3utL8sNpJGqRpkQf0zyTgp1yXIRszucCzQAowVxmMzY3ZaA5y8Y-aeV2Bu7BHLpVI6CMKl7cuVOJ5QHLv7EN8gU8ts-4J3t8TJCXA?key=PqN_g0HdcyYepwEb5e7OGQCR" alt="Screenshot showing the Guide Tools section" width="1600" height="760" loading="lazy"></p>
<h2 id="heading-finding-the-right-tools-tips-for-navigation">Finding the Right Tools: Tips for Navigation</h2>
<h3 id="heading-efficient-search-amp-filtering"><strong>Efficient Search &amp; Filtering</strong></h3>
<p>WebCurate’s search and filtering functions make it simple to find exactly what you need, fast. Whether you’re after an API for a new feature or a project management tool, these features help narrow your options to the most relevant tools quickly and effectively.</p>
<p><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXd7XSYwisbDhNsOim_MAtxnvsQH36z9ZVUkIr8H_84RIv_bDM7-4a6l-BRyV2vfGPsWjKpYnPoJ0lMIlgo5jG_95hTlyd1wNQAv2NCrQUUtNtkaOvzPCDFNiX5kqyxQxpSuCO3f5w?key=PqN_g0HdcyYepwEb5e7OGQCR" alt="Screenshot showing search" width="1600" height="760" loading="lazy"></p>
<h3 id="heading-curated-recommendations"><strong>Curated Recommendations</strong></h3>
<p>What sets WebCurate apart is its thoughtful curation. Instead of suggesting random, popular tools, it presents resources that address real developer needs, based on industry trends and emerging technologies. This means you’re seeing tools that make an impact—tailored to current, practical needs.</p>
<p><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXf1RU5wgtnezPi-om7y63Boeyq9l_-5cCQ6CP6ELxa6cjwjIBDFJ3GEOffl8E7NWe-rX1UMliN67L0BxMJ_H-3w2b4R2yw6eZjpTAKAj0ZAYjHlcuWjimuPNyR9B0PK-pkFo2WdmQ?key=PqN_g0HdcyYepwEb5e7OGQCR" alt="Screenshot showing the &quot;Categories&quot; dropdown" width="1600" height="760" loading="lazy"></p>
<h4 id="heading-example-task-management-tools"><strong>Example: Task Management Tools</strong></h4>
<p>For instance, searching for “task management” within the "Productivity" filter quickly revealed tools aligned with my development approach.</p>
<p><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXe4rPt_A_jeeP55hsdvYx24KB-8-OZZh1LXNDOLtnC7T0BOMbDrH6gRG6QGwOQzcWJBbcbjlqryFXlqX7G9TZeVOrGBYbLbL3nybIZEYkjLnZ2Jb8go-Ie199MTaTrsMHP1j-CrAA?key=PqN_g0HdcyYepwEb5e7OGQCR" alt="Screenshot showing task management tools" width="1600" height="760" loading="lazy"></p>
<p>By using filters for categories like "Development" or "Productivity," WebCurate connects you with tools tailored to your tech stack.</p>
<h2 id="heading-how-you-can-make-the-most-of-webcurate">How You Can Make the Most of WebCurate</h2>
<p>I’ve told you a bit about how WebCurate helped me find essential tools and resources while building <a target="_blank" href="https://kreed.tech">Kreed</a>. But let’s be real, the value of a tool lies in how you use it.</p>
<p>So, if you’re thinking about trying WebCurate out for your next project or even just to optimize your workflow, here’s how you can make the most of it:</p>
<ol>
<li><p><strong>Start with Your Needs</strong>: The first step is identifying what you actually need. Are you a developer trying to optimize your front-end stack? A product manager looking for tools to boost team productivity? Or maybe you’re just exploring new ways to streamline your projects? WebCurate’s search and filtering system allows you to narrow down tools based on what you're looking for, so spend some time defining your needs.</p>
</li>
<li><p><strong>Use the Developer Section to Your Advantage</strong>: For anyone working in tech, <a target="_blank" href="https://webcurate.co/c/developer">the Developer section</a> is a <em>must</em>. It’s tailored to provide the most relevant resources for developers, from libraries and frameworks to APIs and deployment tools. For me, it saved hours of research and trial and error. Don’t just browse the section—dig into it, explore the recommendations, and filter by categories or specific tools you’re interested in.</p>
</li>
<li><p><strong>Filter and Refine Your Search</strong>: WebCurate lets you filter by categories like design, front-end development, back-end tools, and even productivity. When you search, take the time to refine your results so you’re only seeing what’s most relevant. For instance, if you’re building a React app, filter for tools that integrate well with React—WebCurate will show you options that are perfect for your tech stack. And since every tool is vetted by the community, you know you’re not wasting time with gimmicks.</p>
</li>
<li><p><strong>Keep an Open Mind and Explore</strong>: While it’s helpful to focus on exactly what you’re looking for, WebCurate also encourages a bit of exploration outside your comfort zone. You might stumble upon a tool or resource you hadn’t thought of but that could genuinely elevate your project. Just don’t get lost in endless scrolling—keep your objective in mind. It’s easy to get sidetracked exploring, but remember, you’re here to find tools that push your project forward, not to doom scroll your way to zero productivity. </p>
</li>
<li><p>Experiment with New Tools and Stay Updated: Building a product is fundamentally about iteration, and this principle extends to the tools you choose to support it. WebCurate is a dynamic resource that updates <strong>daily</strong> with fresh recommendations, making it a valuable tool for discovering new options. Even if you don't need a new tool right now, it's worth revisiting regularly for innovative ideas that could prove useful in the future.</p>
</li>
</ol>
<h2 id="heading-essential-tools-i-discovered-on-webcurate">Essential Tools I Discovered on WebCurate</h2>
<p>Here’s a rundown of a few tools that I found interesting on WebCurate—some are longtime favourites, while others were discoveries that have quickly become essentials.</p>
<h4 id="heading-tools-i-already-use-and-still-love"><strong>Tools I Already Use (and Still Love)</strong></h4>
<ul>
<li><p><a target="_blank" href="https://supabase.com/"><strong>Supabase</strong></a>: An open-source Firebase alternative that simplifies backend development with real-time updates and intuitive database management.</p>
</li>
<li><p><a target="_blank" href="https://gsap.com/"><strong>GSAP</strong></a>: A powerful animation library for creating smooth, high-performance animations (<a target="_blank" href="https://www.freecodecamp.org/news/build-an-interactive-accordion-component-with-react-and-gsap/">I even wrote an article about how I use it</a>!).</p>
</li>
<li><p><a target="_blank" href="https://chromewebstore.google.com/detail/json-viewer/gbmdgpbipfallnflgajpaliibnhdgobh"><strong>JsonViewer</strong></a>: A practical tool for viewing and formatting JSON data, making debugging and visualization easier.</p>
</li>
<li><p><a target="_blank" href="https://caniuse.com/"><strong>CanIUse</strong></a>: An essential resource for checking browser compatibility across HTML5, CSS3, SVG, and more—perfect for ensuring cross-platform support.</p>
</li>
</ul>
<h4 id="heading-new-tools-i-use-often-or-plan-on-using-soon"><strong>New Tools I Use Often or Plan on Using Soon</strong></h4>
<ul>
<li><p><a target="_blank" href="https://chromewebstore.google.com/detail/pesticide-for-chrome/bakpbgckdnepkmkeaiomhmfcnejndkbi?hl=en"><strong>Pesticide for Chrome</strong></a>: A Chrome extension that outlines page elements, helping spot layout issues and verify alignment quickly.</p>
</li>
<li><p><a target="_blank" href="https://wind-ui.com/"><strong>WindUI</strong></a>: A component library styled with Tailwind CSS, that speeds up development without compromising design quality.</p>
</li>
<li><p><a target="_blank" href="https://mobbin.com/"><strong>Mobbin</strong></a>: A curated collection of mobile design patterns, offering inspiration to refine and elevate mobile UI elements.</p>
</li>
<li><p><a target="_blank" href="https://www.mightymeld.com/"><strong>Mightly Meld</strong></a>: A collaborative design tool for React that makes feedback gathering and design iteration faster and more streamlined.</p>
</li>
<li><p><a target="_blank" href="https://www.rowy.io/"><strong>Rowy</strong></a>: A no-code platform connecting directly to databases, allowing for rapid development and deployment of data-driven applications without extensive code.</p>
</li>
</ul>
<h2 id="heading-wrapping-it-up">Wrapping It Up</h2>
<p>At the end of the day, building a startup is a mix of hustle, luck, and learning on the fly. And this article just represents a nerd like me geeking out over tools that made a difference (and resisting the urge to gatekeep 😂).</p>
<p>Finding WebCurate didn’t magically solve all my challenges, but it did cut down on the noise and brought useful resources to my fingertips—a massive win when every minute counts.</p>
<p>If you’re on your startup journey, know this is only part of the ride. Maybe one day I’ll share the full highs and lows of being a founder—assuming I get a break from being Batman 🦇. </p>
<h3 id="heading-like-my-articles">Like my articles?</h3>
<p>Feel free to <a target="_blank" href="https://www.buymeacoffee.com/JajaDavid">buy me a coffee here</a>, to keep my brain chugging and provide more articles like this.</p>
<p>Want to connect?</p>
<ul>
<li><p>Twitter / X: <a target="_blank" href="https://twitter.com/JajaDavid8">@jajadavid8</a></p>
</li>
<li><p>LinkedIn: <a target="_blank" href="https://www.linkedin.com/in/david-jaja-8084251b4/">David Jaja</a></p>
</li>
<li><p>Email: Jajadavidjid@gmail.com</p>
</li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Improve User Experience with Optimistic UI and SWR ]]>
                </title>
                <description>
                    <![CDATA[ Have you ever noticed how some apps feel like they can read your mind? You click a button, and before you can even blink, it's done – no loading screens, no waiting around. It's like magic, right? Well, let me tell you a little secret: that's the pow... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/improve-user-experience-with-optimistic-ui-swr/</link>
                <guid isPermaLink="false">66bb8911b0d3ac3d7acde3db</guid>
                
                    <category>
                        <![CDATA[ UI Design ]]>
                    </category>
                
                    <category>
                        <![CDATA[ user experience ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ David Jaja ]]>
                </dc:creator>
                <pubDate>Tue, 09 Jul 2024 22:33:50 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/07/Article-cover.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Have you ever noticed how some apps feel like they can read your mind? You click a button, and before you can even blink, it's done – no loading screens, no waiting around. It's like magic, right? Well, let me tell you a little secret: that's the power of Optimistic UI.</p>
<p>In this article, we'll dive into Optimistic UI and explore how it works and keeps your web experience smooth as butter. We'll build a simple task app together that'll show how Optimistic UI can help turn mundane tasks into lightning-fast interactions that leave your users feeling happy.</p>
<h3 id="heading-prerequisites">Prerequisites</h3>
<ul>
<li>Fundamentals of JavaScript and React</li>
<li>Fundamentals of Async programming and Axios</li>
<li>Knowledge of hook-oriented fetch libraries would also be beneficial</li>
</ul>
<h2 id="heading-what-well-cover"><strong>What We'll Cover:</strong></h2>
<ol>
<li><a class="post-section-overview" href="#heading-what-is-optimistic-ui">What is Optimistic UI?</a></li>
<li><a class="post-section-overview" href="#heading-why-does-optimistic-ui-matter">Why Does Optimistic UI Matter?</a></li>
<li><a class="post-section-overview" href="#heading-other-benefits-of-optimistic-ui">Other Benefits of Optimistic UI</a></li>
<li><a class="post-section-overview" href="#heading-introducing-swr-stale-while-revalidate">Introducing SWR: Stale-While-Revalidate</a></li>
<li><a class="post-section-overview" href="#heading-how-to-set-up-the-environment">How to Set Up the Environment</a></li>
<li><a class="post-section-overview" href="#building-the-task-app-ui">How to Build the Task App UI</a><br>– <a class="post-section-overview" href="#heading-regular-crud-ui">Regular CRUD UI</a><br>– <a class="post-section-overview" href="#heading-optimistic-crud-ui">Optimistic CRUD UI</a></li>
<li><a class="post-section-overview" href="#heading-drawbacks-of-optimistic-ui">Drawbacks of Optimistic UI</a></li>
<li><a class="post-section-overview" href="#heading-ideal-use-cases-for-optimistic-ui">Ideal Use Cases for Optimistic UI</a></li>
<li><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></li>
</ol>
<h2 id="heading-what-is-optimistic-ui">What is Optimistic UI?</h2>
<p>At its core, Optimistic UI is all about keeping your app feeling snappy and responsive, even when a lot is happening behind the scenes. It's like having a superpower that lets your app predict the future – well, sort of.</p>
<p>When you perform an action in your app – whether it's adding a new item to a list or updating a profile – Optimistic UI kicks in to make it happen right away, without waiting for confirmation from the server. It's the ultimate optimist, always assuming everything will work out just fine.</p>
<h2 id="heading-why-does-optimistic-ui-matter">Why Does Optimistic UI Matter?</h2>
<p>So why should you care about Optimistic UI? Simple: because it's the secret sauce that turns good apps into great ones. </p>
<p>Think about it: when you click a button, you expect something to happen – and you expect it to happen fast. That's where Optimistic UI shines. By giving your users instant feedback and keeping your app feeling snappy, Optimistic UI enhances the overall user experience. </p>
<p>No more staring at loading screens or wondering if your click <em>actually</em> did anything – with Optimistic UI, every action feels easy and effective.</p>
<h2 id="heading-other-benefits-of-optimistic-ui">Other Benefits of Optimistic UI</h2>
<ol>
<li><strong>Reduced Perceived Latency</strong>: Optimistic UI reduces the perceived latency of actions by displaying changes immediately without waiting for server confirmation. This creates a perception of faster response times, even if server communication takes longer.</li>
<li><strong>Improved Responsiveness</strong>: Optimistic UI allows users to interact with the app continuously without interruptions from loading spinners or waiting screens. This uninterrupted flow enhances the overall responsiveness of the application.</li>
<li><strong>Support for Complex Interactions</strong>: Optimistic UI helps complex interactions, such as drag-and-drop, multi-step processes, and real-time collaboration, feel fluid and intuitive. This flexibility opens up possibilities for innovative features and functionalities in the app.</li>
<li><strong>Increased User Engagement</strong>: The responsiveness and interactivity provided by Optimistic UI can lead to increased user engagement and retention. Users are more likely to return to an app that provides a smooth and enjoyable experience.</li>
</ol>
<h2 id="heading-introducing-swr-stale-while-revalidate">Introducing SWR: Stale-While-Revalidate</h2>
<p>Before we dive into the implementation, let's take a moment to talk about SWR. SWR is a lightweight React Hook library for data fetching. SWR stands for <a target="_blank" href="https://swr.vercel.app/examples/optimistic-ui">Stale-While-Revalidate</a>, and it strikes the perfect balance between performance and freshness when fetching data in your React applications.</p>
<p>SWR also automatically revalidates data in the background while still serving stale data from the cache. This means your app stays fast and responsive, even when fetching fresh data from the server.</p>
<p>But that's not all – SWR also supports key features like caching, pagination, and error handling, making it a powerful tool in your arsenal for building fast, reliable web applications as well as implementing Optimistic UI.</p>
<h2 id="heading-how-to-set-up-the-environment">How to Set Up the Environment</h2>
<p>I've prepared a GitHub repository with starter files to speed things up. Simply <a target="_blank" href="https://github.com/Daiveedjay/Optimistic-UI-with-SWR/tree/starter">clone this repo</a> and install the dependencies.</p>
<p>The starter code consists of the basic JSX components required, as well as some basic <a target="_blank" href="https://axios-http.com/docs/intro">Axios</a> functions for performing CRUD operations. After installing all the necessary packages with <code>npm i</code>, open your terminal and start up your local endpoint using <a target="_blank" href="https://www.npmjs.com/package/json-server">json-server</a>.</p>
<pre><code class="lang-bash">npx json-server data/db.json -p 3500
</code></pre>
<p>To see all your data present, head over to that route:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/07/1-Showing-initial-data.png" alt="Image" width="600" height="400" loading="lazy">
<em>Showing initial data</em></p>
<h2 id="heading-how-to-build-the-task-app-ui">How to Build the Task App UI</h2>
<p>In this section, we’ll first implement CRUD applications without Optimistic UI and then with Optimistic UI to show the differences between them.</p>
<h3 id="heading-regular-crud-ui">Regular CRUD UI</h3>
<p>Start by heading over to your <code>TaskContainer</code> component, then use the <code>useSWR</code> hook to call your fetch function.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> {
    isLoading,
    error,
    <span class="hljs-attr">data</span>: tasks,
    mutate,
  } = useSWR(cacheKey, fetchTasks, {
    <span class="hljs-attr">onSuccess</span>: <span class="hljs-function">(<span class="hljs-params">data</span>) =&gt;</span>
      data.sort(<span class="hljs-function">(<span class="hljs-params">a, b</span>) =&gt;</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(b.createdAt) - <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(a.createdAt)),
  });
</code></pre>
<p>SWR uses a similar data fetching hook and pattern to other libraries such as <a target="_blank" href="https://tanstack.com/query/latest/docs/framework/react/overview">React Query (TanStack Query)</a> and <a target="_blank" href="https://redux-toolkit.js.org/rtk-query/overview">Redux Toolkit Query</a>. This hook fetching pattern often returns a loading state, an error state, your fetched data (if any) and a mutation function (but more about that later).</p>
<p><strong>Note</strong>: The <code>cacheKey</code> is a unique key used to notify SWR when and where to re-call your function. The <code>onSuccess</code> function is a method used to trigger another action when the fetch is successful – in this case, sorting the data in descending order.</p>
<p>With your data back, you can now create the JSX markup.</p>
<pre><code class="lang-jsx"><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">"flex flex-col gap-8 p-4"</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"p-4 shadow-lg "</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex flex-col gap-4 "</span>&gt;</span>
            {tasks &amp;&amp;
              tasks.map((task, index) =&gt; {
                return (
                  <span class="hljs-tag">&lt;<span class="hljs-name">div</span>
                    <span class="hljs-attr">key</span>=<span class="hljs-string">{task.id}</span>
                    <span class="hljs-attr">className</span>=<span class="hljs-string">"flex gap-4 items-center py-2 px-6 rounded-md bg-[#74a0a6]"</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">label</span>
                        <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">task-</span>${<span class="hljs-attr">task.id</span>}`}
                        <span class="hljs-attr">key</span>=<span class="hljs-string">{task.id}</span>
                        <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">flex</span> <span class="hljs-attr">gap-4</span> <span class="hljs-attr">text-</span>[<span class="hljs-attr">14px</span>] <span class="hljs-attr">items-center</span> <span class="hljs-attr">font-bold</span> <span class="hljs-attr">list-none</span> <span class="hljs-attr">p-4</span> <span class="hljs-attr">rounded</span> <span class="hljs-attr">bg-</span>[#<span class="hljs-attr">88adb3</span>] <span class="hljs-attr">cursor-pointer</span> <span class="hljs-attr">hover:bg-</span>[#<span class="hljs-attr">609299</span>]`}&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"inline-flex items-center"</span>&gt;</span>
                          <span class="hljs-tag">&lt;<span class="hljs-name">label</span>
                            <span class="hljs-attr">className</span>=<span class="hljs-string">"relative flex items-center p-3 rounded-full cursor-pointer"</span>
                            <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"checkbox"</span>&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
                              <span class="hljs-attr">type</span>=<span class="hljs-string">"checkbox"</span>
                              <span class="hljs-attr">name</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">task-</span>${<span class="hljs-attr">task.id</span>}`}
                              <span class="hljs-attr">id</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">task-</span>${<span class="hljs-attr">task.id</span>}`}
                              <span class="hljs-attr">className</span>=<span class="hljs-string">"before:content[''] peer relative h-5 w-5 cursor-pointer appearance-none rounded-md border border-[#edebd9] transition-all before:absolute before:top-2/4 before:left-2/4 before:block before:h-12 before:w-12 before:-translate-y-2/4 before:-translate-x-2/4 before:rounded-full before:bg-blue-gray-500 before:opacity-0 before:transition-opacity checked:border-lines checked:bg-[#545240] checked:before:bg-[#edebd9] hover:before:opacity-10 before:checked:hover:before:opacity-10 "</span>
                              <span class="hljs-attr">checked</span>=<span class="hljs-string">{task.completed}</span>
                                                         /&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"absolute transition-opacity opacity-0 pointer-events-none text-stone-100 top-2/4 left-2/4 -translate-y-2/4 -translate-x-2/4 peer-checked:opacity-100"</span>&gt;</span>
                              <span class="hljs-tag">&lt;<span class="hljs-name">svg</span>
                                <span class="hljs-attr">xmlns</span>=<span class="hljs-string">"http://www.w3.org/2000/svg"</span>
                                <span class="hljs-attr">className</span>=<span class="hljs-string">"h-3.5 w-3.5"</span>
                                <span class="hljs-attr">viewBox</span>=<span class="hljs-string">"0 0 20 20"</span>
                                <span class="hljs-attr">fill</span>=<span class="hljs-string">"currentColor"</span>
                                <span class="hljs-attr">stroke</span>=<span class="hljs-string">"currentColor"</span>
                                <span class="hljs-attr">strokeWidth</span>=<span class="hljs-string">"1"</span>&gt;</span>
                                <span class="hljs-tag">&lt;<span class="hljs-name">path</span>
                                  <span class="hljs-attr">fillRule</span>=<span class="hljs-string">"evenodd"</span>
                                  <span class="hljs-attr">d</span>=<span class="hljs-string">"M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z"</span>
                                  <span class="hljs-attr">clipRule</span>=<span class="hljs-string">"evenodd"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">path</span>&gt;</span>
                              <span class="hljs-tag">&lt;/<span class="hljs-name">svg</span>&gt;</span>
                            <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                          <span class="hljs-tag">&lt;/<span class="hljs-name">label</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">label</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 class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-xl font-bold text-[#161515] "</span>&gt;</span>
                        {task.title}
                      <span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
                      <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-sm font-semibold text-[#42403f] "</span>&gt;</span>
                        {task.description}
                      <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
                      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex gap-2 mt-2 text-xs font-bold"</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex items-center "</span>&gt;</span>
                          <span class="hljs-tag">&lt;<span class="hljs-name">img</span>
                            <span class="hljs-attr">src</span>=<span class="hljs-string">{userImages[index]}</span>
                            <span class="hljs-attr">alt</span>=<span class="hljs-string">""</span>
                            <span class="hljs-attr">className</span>=<span class="hljs-string">"w-10 h-10 rounded-full "</span>
                          /&gt;</span>
                          <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span> {task.assignedTo}<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">div</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>
                      <span class="hljs-attr">className</span>=<span class="hljs-string">"p-2 ml-auto rounded-full cursor-pointer hover:bg-red-300"</span>
                    &gt;</span>
                      <span class="hljs-tag">&lt;<span class="hljs-name">FaTrash</span> <span class="hljs-attr">color</span>=<span class="hljs-string">"#545240"</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 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 class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>

  );
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/07/2-UI-after-fetcing-data.png" alt="Image" width="600" height="400" loading="lazy">
<em>UI after data fetching</em></p>
<p>After that, head into your <code>Taskform</code> component and create a form UI for creating new tasks.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> { addSingleTask } <span class="hljs-keyword">from</span> <span class="hljs-string">"./services/api"</span>;
<span class="hljs-keyword">import</span> toast <span class="hljs-keyword">from</span> <span class="hljs-string">"react-hot-toast"</span>;
<span class="hljs-keyword">import</span> { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Taskform</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [title, setTitle] = useState(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> [description, setDescription] = useState(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> [assignedTo, setAssignedTo] = useState(<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">"bg-[#74a0a6] p-4 rounded-md"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex flex-col w-full gap-2 "</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"title"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"font-bold "</span>&gt;</span>Title<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
            <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span>
            <span class="hljs-attr">className</span>=<span class="hljs-string">"w-full font-medium  focus:outline-[#74a0a6] focus-within:outline-[#74a0a6] p-1 bg-transparent border rounded-md"</span>
            <span class="hljs-attr">value</span>=<span class="hljs-string">{title}</span>
            <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setTitle(e.target.value)}
          /&gt;
        <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"description"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"font-bold "</span>&gt;</span>Description<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
            <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span>
            <span class="hljs-attr">className</span>=<span class="hljs-string">"w-full font-medium  focus:outline-[#74a0a6] focus-within:outline-[#74a0a6] p-1 bg-transparent border rounded-md"</span>
            <span class="hljs-attr">value</span>=<span class="hljs-string">{description}</span>
            <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setDescription(e.target.value)}
          /&gt;
        <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"assignedTo"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"font-bold "</span>&gt;</span>Assigned To<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
            <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span>
            <span class="hljs-attr">className</span>=<span class="hljs-string">"w-full font-medium  focus:outline-[#74a0a6] focus-within:outline-[#74a0a6] p-1 bg-transparent border rounded-md"</span>
            <span class="hljs-attr">value</span>=<span class="hljs-string">{assignedTo}</span>
            <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setAssignedTo(e.target.value)}
          /&gt;
        <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"p-2 mt-3 border text-white rounded-md w-max hover:bg-white hover:text-[#74a0a6]"</span>&gt;</span>
          Add
        <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<p>After that, import it into your <code>TaskContainer</code> component.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">return</span> (

      &lt;div className="flex flex-col gap-8 p-4"&gt;
        &lt;Taskform /&gt;
        &lt;div className="p-4 shadow-lg "&gt;
          &lt;div className="flex flex-col gap-4 "&gt;
            {tasks &amp;&amp;
              tasks.map((task, index) =&gt; {
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/07/3-UI-with-Form-added.png" alt="Image" width="600" height="400" loading="lazy">
<em>UI with Form added</em></p>
<p>To add a new task, create a handler function in the <code>Taskform</code>, then import your <code>POST</code> function from your API file.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> addTaskMutation = <span class="hljs-keyword">async</span> (e) =&gt; {
    e.preventDefault();
    <span class="hljs-keyword">const</span> createdAt = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().toISOString(); <span class="hljs-comment">// Get current timestamp as a string</span>

    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">await</span> addSingleTask({
        title,
        description,
        assignedTo,
        <span class="hljs-attr">completed</span>: <span class="hljs-literal">false</span>,
        createdAt,
      });

      toast.success(<span class="hljs-string">"Task added succesfully."</span>);
      setTitle(<span class="hljs-string">""</span>);
      setDescription(<span class="hljs-string">""</span>);
      setAssignedTo(<span class="hljs-string">""</span>);
    } <span class="hljs-keyword">catch</span> (err) {
      toast.error(<span class="hljs-string">"Failed to add the new task."</span>);
    }
  };
</code></pre>
<p>Finally, call the <code>mutate</code> function after your <code>POST</code> function call to enable SWR to invalidate your current data and make a new request. You can get this mutate function from the <code>useSWR</code> hook in the <code>TaskContainer</code>, then pass it through props to the form.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> {
    isLoading,
    error,
    <span class="hljs-attr">data</span>: tasks,
    mutate,
  } = useSWR(cacheKey, fetchTasks, {
    <span class="hljs-attr">onSuccess</span>: <span class="hljs-function">(<span class="hljs-params">data</span>) =&gt;</span>
      data.sort(<span class="hljs-function">(<span class="hljs-params">a, b</span>) =&gt;</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(b.createdAt) - <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(a.createdAt)),
  });
  <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">"flex flex-col gap-8 p-4"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Taskform</span> <span class="hljs-attr">mutate</span>=<span class="hljs-string">{mutate}</span> /&gt;</span></span>
</code></pre>
<p>Then call it in the <code>TaskForm</code>.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> { addSingleTask } <span class="hljs-keyword">from</span> <span class="hljs-string">"./services/api"</span>;
<span class="hljs-keyword">import</span> toast <span class="hljs-keyword">from</span> <span class="hljs-string">"react-hot-toast"</span>;
<span class="hljs-keyword">import</span> { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Taskform</span>(<span class="hljs-params">{ mutate }</span>) </span>{
  <span class="hljs-keyword">const</span> [title, setTitle] = useState(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> [description, setDescription] = useState(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> [assignedTo, setAssignedTo] = useState(<span class="hljs-string">""</span>);

  <span class="hljs-keyword">const</span> addTaskMutation = <span class="hljs-keyword">async</span> (e) =&gt; {
    e.preventDefault();
    <span class="hljs-keyword">const</span> createdAt = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().toISOString();
    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">await</span> addSingleTask({
        title,
        description,
        assignedTo,
        <span class="hljs-attr">completed</span>: <span class="hljs-literal">false</span>,
        createdAt,
      });
      mutate();

      toast.success(<span class="hljs-string">"Task added succesfully."</span>);
      setTitle(<span class="hljs-string">""</span>);
      setDescription(<span class="hljs-string">""</span>);
      setAssignedTo(<span class="hljs-string">""</span>);
    } <span class="hljs-keyword">catch</span> (err) {
      toast.error(<span class="hljs-string">"Failed to add the new task."</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">"bg-[#74a0a6] p-4 rounded-md"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">form</span>
        <span class="hljs-attr">className</span>=<span class="hljs-string">"flex flex-col w-full gap-2 "</span>
        <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{(e)</span> =&gt;</span> addTaskMutation(e)}&gt;
        <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"title"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"font-bold "</span>&gt;</span>Title<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
            <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span>
            <span class="hljs-attr">className</span>=<span class="hljs-string">"w-full font-medium  focus:outline-[#74a0a6] focus-within:outline-[#74a0a6] p-1 bg-transparent border rounded-md"</span>
            <span class="hljs-attr">value</span>=<span class="hljs-string">{title}</span>
            <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setTitle(e.target.value)}
          /&gt;
        <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"description"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"font-bold "</span>&gt;</span>Description<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
            <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span>
            <span class="hljs-attr">className</span>=<span class="hljs-string">"w-full font-medium  focus:outline-[#74a0a6] focus-within:outline-[#74a0a6] p-1 bg-transparent border rounded-md"</span>
            <span class="hljs-attr">value</span>=<span class="hljs-string">{description}</span>
            <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setDescription(e.target.value)}
          /&gt;
        <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"assignedTo"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"font-bold "</span>&gt;</span>Assigned To<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
            <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span>
            <span class="hljs-attr">className</span>=<span class="hljs-string">"w-full font-medium  focus:outline-[#74a0a6] focus-within:outline-[#74a0a6] p-1 bg-transparent border rounded-md"</span>
            <span class="hljs-attr">value</span>=<span class="hljs-string">{assignedTo}</span>
            <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setAssignedTo(e.target.value)}
          /&gt;
        <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"p-2 mt-3 border text-white rounded-md w-max hover:bg-white hover:text-[#74a0a6]"</span>&gt;</span>
          Add
        <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<p>Testing your component now gives the following result:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/07/1-Regular-Create-Operation.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Regular Create Operation</em></p>
<p>As you can see, the list is updated after each form submission. But this still doesn’t highlight our need for optimistic UI. You’re probably thinking, if the operation happened that fast, why bother with Optimistic UI?</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/07/2-What-s-the-point.gif" alt="Image" width="600" height="400" loading="lazy">
<em>What's the point gif</em></p>
<p>Well, for starters, no real-world application is ever going to beat the speed of your local JSON server, as the data is readily available to you and users often have unstable network connections.</p>
<p>Let's slow down the fetch to illustrate a real-world data request better. This better simulates a real-world scenario as users often come from different locations that have varying internet speeds.</p>
<p>Start by creating a delay function that runs before each of your function calls.</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">"axios"</span>;

<span class="hljs-keyword">const</span> tasksApi = axios.create({
  <span class="hljs-attr">baseURL</span>: <span class="hljs-string">"http://localhost:3500"</span>,
});

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> tasksUrlEndpoint = <span class="hljs-string">"/tasks"</span>;

<span class="hljs-keyword">const</span> delay = <span class="hljs-function">() =&gt;</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function">(<span class="hljs-params">res</span>) =&gt;</span> <span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">() =&gt;</span> res(), <span class="hljs-number">1200</span>));

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> fetchTasks = <span class="hljs-keyword">async</span> () =&gt; {
   <span class="hljs-keyword">await</span> delay();
  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> tasksApi.get(tasksUrlEndpoint);
  <span class="hljs-keyword">return</span> response.data;
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> addSingleTask = <span class="hljs-keyword">async</span> ({
  title,
  description,
  completed,
  assignedTo,
  createdAt,
}) =&gt; {
  <span class="hljs-keyword">await</span> delay();
  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> tasksApi.post(tasksUrlEndpoint, {
    title,
    description,
    completed,
    assignedTo,
    createdAt,
  });
  <span class="hljs-keyword">return</span> response.data;
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> updateSingleTask = <span class="hljs-keyword">async</span> (task) =&gt; {
  <span class="hljs-keyword">await</span> delay();
  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> tasksApi.patch(<span class="hljs-string">`<span class="hljs-subst">${tasksUrlEndpoint}</span>/<span class="hljs-subst">${task.id}</span>`</span>, task);
  <span class="hljs-keyword">return</span> response.data;
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> deleteSingleTask = <span class="hljs-keyword">async</span> ({ id }) =&gt; {
  <span class="hljs-keyword">await</span> delay();
  <span class="hljs-keyword">return</span> <span class="hljs-keyword">await</span> tasksApi.delete(<span class="hljs-string">`<span class="hljs-subst">${tasksUrlEndpoint}</span>/<span class="hljs-subst">${id}</span>`</span>, id);
};
</code></pre>
<p>Then attempt your create operation again.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/07/3-Create-operation-after-delay.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Create operation after delay</em></p>
<p>As you may have noticed, the create operation was only fired after the delay function (spanning 1.2 seconds) finished running, which caused a brief spell of inactivity on the screen. </p>
<p>The usual way to handle those periods between loading is usually a loading spinner or indicator telling you that some background activity is running. But this often disrupts your flow when working in the application, and quite frankly is disappointing.</p>
<p>The same static effect can be seen in the update operation, where users have to wait for server confirmation to see fresh data.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> updateTaskMutation = <span class="hljs-keyword">async</span> (updatedTask) =&gt; {
    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">await</span> updateSingleTask(updatedTask);
      mutate();
      toast.success(<span class="hljs-string">"Successfully updated task"</span>);
    } <span class="hljs-keyword">catch</span> (err) {
      toast.error(<span class="hljs-string">"Failed to update the task."</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">"flex flex-col gap-8 p-4"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Taskform</span> <span class="hljs-attr">mutate</span>=<span class="hljs-string">{mutate}</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"p-4 shadow-lg "</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex flex-col gap-4 "</span>&gt;</span>
          {tasks &amp;&amp;
            tasks.map((task, index) =&gt; {
              return (
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span>
                  <span class="hljs-attr">key</span>=<span class="hljs-string">{task.id}</span>
                  <span class="hljs-attr">className</span>=<span class="hljs-string">"flex gap-4 items-center py-2 px-6 rounded-md bg-[#74a0a6]"</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">label</span>
                      <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">task-</span>${<span class="hljs-attr">task.id</span>}`}
                      <span class="hljs-attr">key</span>=<span class="hljs-string">{task.id}</span>
                      <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">flex</span> <span class="hljs-attr">gap-4</span> <span class="hljs-attr">text-</span>[<span class="hljs-attr">14px</span>] <span class="hljs-attr">items-center</span> <span class="hljs-attr">font-bold</span> <span class="hljs-attr">list-none</span> <span class="hljs-attr">p-4</span> <span class="hljs-attr">rounded</span> <span class="hljs-attr">bg-</span>[#<span class="hljs-attr">88adb3</span>] <span class="hljs-attr">cursor-pointer</span> <span class="hljs-attr">hover:bg-</span>[#<span class="hljs-attr">609299</span>]`}&gt;</span>
                      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"inline-flex items-center"</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">label</span>
                          <span class="hljs-attr">className</span>=<span class="hljs-string">"relative flex items-center p-3 rounded-full cursor-pointer"</span>
                          <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"checkbox"</span>&gt;</span>
                          <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
                            <span class="hljs-attr">type</span>=<span class="hljs-string">"checkbox"</span>
                            <span class="hljs-attr">name</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">task-</span>${<span class="hljs-attr">task.id</span>}`}
                            <span class="hljs-attr">id</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">task-</span>${<span class="hljs-attr">task.id</span>}`}
                            <span class="hljs-attr">className</span>=<span class="hljs-string">"before:content[''] peer relative h-5 w-5 cursor-pointer appearance-none rounded-md border border-[#edebd9] transition-all before:absolute before:top-2/4 before:left-2/4 before:block before:h-12 before:w-12 before:-translate-y-2/4 before:-translate-x-2/4 before:rounded-full before:bg-blue-gray-500 before:opacity-0 before:transition-opacity checked:border-lines checked:bg-[#545240] checked:before:bg-[#edebd9] hover:before:opacity-10 before:checked:hover:before:opacity-10 "</span>
                            <span class="hljs-attr">checked</span>=<span class="hljs-string">{task.completed</span> === <span class="hljs-string">true}</span>
                            <span class="hljs-attr">onChange</span>=<span class="hljs-string">{()</span> =&gt;</span>
                              updateTaskMutation({
                                ...task,
                                completed: !task.completed,
                              })
                            }
                          /&gt;
                          <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"absolute transition-opacity opacity-0 pointer-events-none text-stone-100 top-2/4 left-2/4 -translate-y-2/4 -translate-x-2/4 peer-checked:opacity-100"</span>&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">svg</span>
                              <span class="hljs-attr">xmlns</span>=<span class="hljs-string">"http://www.w3.org/2000/svg"</span>
                              <span class="hljs-attr">className</span>=<span class="hljs-string">"h-3.5 w-3.5"</span>
                              <span class="hljs-attr">viewBox</span>=<span class="hljs-string">"0 0 20 20"</span>
                              <span class="hljs-attr">fill</span>=<span class="hljs-string">"currentColor"</span>
                              <span class="hljs-attr">stroke</span>=<span class="hljs-string">"currentColor"</span>
                              <span class="hljs-attr">strokeWidth</span>=<span class="hljs-string">"1"</span>&gt;</span>
                              <span class="hljs-tag">&lt;<span class="hljs-name">path</span>
                                <span class="hljs-attr">fillRule</span>=<span class="hljs-string">"evenodd"</span>
                                <span class="hljs-attr">d</span>=<span class="hljs-string">"M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z"</span>
                                <span class="hljs-attr">clipRule</span>=<span class="hljs-string">"evenodd"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">path</span>&gt;</span>
                            <span class="hljs-tag">&lt;/<span class="hljs-name">svg</span>&gt;</span>
                          <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                        <span class="hljs-tag">&lt;/<span class="hljs-name">label</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">label</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 class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-xl font-bold text-[#161515] "</span>&gt;</span>
                      {task.title}
                    <span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-sm font-semibold text-[#42403f] "</span>&gt;</span>
                      {task.description}
                    <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex gap-2 mt-2 text-xs font-bold"</span>&gt;</span>
                      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex items-center "</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">img</span>
                          <span class="hljs-attr">src</span>=<span class="hljs-string">{userImages[index]}</span>
                          <span class="hljs-attr">alt</span>=<span class="hljs-string">""</span>
                          <span class="hljs-attr">className</span>=<span class="hljs-string">"w-10 h-10 rounded-full "</span>
                        /&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span> {task.assignedTo}<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">div</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>
                    <span class="hljs-attr">className</span>=<span class="hljs-string">"p-2 ml-auto rounded-full cursor-pointer hover:bg-red-300"</span>
                   &gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">FaTrash</span> <span class="hljs-attr">color</span>=<span class="hljs-string">"#545240"</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 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 class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/07/4-Update-operation-after-delay.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Update operation after delay</em></p>
<p>And in the delete operation, which also waits for server conformation to rehydrate the page.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> deleteTaskMutation = <span class="hljs-keyword">async</span> ({ id }) =&gt; {
    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">await</span> deleteSingleTask({ id });
      mutate();
      toast.success(<span class="hljs-string">"Successfully deleted task"</span>);
    } <span class="hljs-keyword">catch</span> (err) {
      toast.error(<span class="hljs-string">"Failed to delete the task."</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">"flex flex-col gap-8 p-4"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Taskform</span> <span class="hljs-attr">mutate</span>=<span class="hljs-string">{mutate}</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"p-4 shadow-lg "</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex flex-col gap-4 "</span>&gt;</span>
          {tasks &amp;&amp;
            tasks.map((task, index) =&gt; {
              return (
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span>
                  <span class="hljs-attr">key</span>=<span class="hljs-string">{task.id}</span>
                  <span class="hljs-attr">className</span>=<span class="hljs-string">"flex gap-4 items-center py-2 px-6 rounded-md bg-[#74a0a6]"</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">label</span>
                      <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">task-</span>${<span class="hljs-attr">task.id</span>}`}
                      <span class="hljs-attr">key</span>=<span class="hljs-string">{task.id}</span>
                      <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">flex</span> <span class="hljs-attr">gap-4</span> <span class="hljs-attr">text-</span>[<span class="hljs-attr">14px</span>] <span class="hljs-attr">items-center</span> <span class="hljs-attr">font-bold</span> <span class="hljs-attr">list-none</span> <span class="hljs-attr">p-4</span> <span class="hljs-attr">rounded</span> <span class="hljs-attr">bg-</span>[#<span class="hljs-attr">88adb3</span>] <span class="hljs-attr">cursor-pointer</span> <span class="hljs-attr">hover:bg-</span>[#<span class="hljs-attr">609299</span>]`}&gt;</span>
                      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"inline-flex items-center"</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">label</span>
                          <span class="hljs-attr">className</span>=<span class="hljs-string">"relative flex items-center p-3 rounded-full cursor-pointer"</span>
                          <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"checkbox"</span>&gt;</span>
                          <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
                            <span class="hljs-attr">type</span>=<span class="hljs-string">"checkbox"</span>
                            <span class="hljs-attr">name</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">task-</span>${<span class="hljs-attr">task.id</span>}`}
                            <span class="hljs-attr">id</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">task-</span>${<span class="hljs-attr">task.id</span>}`}
                            <span class="hljs-attr">className</span>=<span class="hljs-string">"before:content[''] peer relative h-5 w-5 cursor-pointer appearance-none rounded-md border border-[#edebd9] transition-all before:absolute before:top-2/4 before:left-2/4 before:block before:h-12 before:w-12 before:-translate-y-2/4 before:-translate-x-2/4 before:rounded-full before:bg-blue-gray-500 before:opacity-0 before:transition-opacity checked:border-lines checked:bg-[#545240] checked:before:bg-[#edebd9] hover:before:opacity-10 before:checked:hover:before:opacity-10 "</span>
                            <span class="hljs-attr">checked</span>=<span class="hljs-string">{task.completed</span> === <span class="hljs-string">true}</span>
                            <span class="hljs-attr">onChange</span>=<span class="hljs-string">{()</span> =&gt;</span>
                              updateTaskMutation({
                                ...task,
                                completed: !task.completed,
                              })
                            }
                          /&gt;
                          <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"absolute transition-opacity opacity-0 pointer-events-none text-stone-100 top-2/4 left-2/4 -translate-y-2/4 -translate-x-2/4 peer-checked:opacity-100"</span>&gt;</span>
                            <span class="hljs-tag">&lt;<span class="hljs-name">svg</span>
                              <span class="hljs-attr">xmlns</span>=<span class="hljs-string">"http://www.w3.org/2000/svg"</span>
                              <span class="hljs-attr">className</span>=<span class="hljs-string">"h-3.5 w-3.5"</span>
                              <span class="hljs-attr">viewBox</span>=<span class="hljs-string">"0 0 20 20"</span>
                              <span class="hljs-attr">fill</span>=<span class="hljs-string">"currentColor"</span>
                              <span class="hljs-attr">stroke</span>=<span class="hljs-string">"currentColor"</span>
                              <span class="hljs-attr">strokeWidth</span>=<span class="hljs-string">"1"</span>&gt;</span>
                              <span class="hljs-tag">&lt;<span class="hljs-name">path</span>
                                <span class="hljs-attr">fillRule</span>=<span class="hljs-string">"evenodd"</span>
                                <span class="hljs-attr">d</span>=<span class="hljs-string">"M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z"</span>
                                <span class="hljs-attr">clipRule</span>=<span class="hljs-string">"evenodd"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">path</span>&gt;</span>
                            <span class="hljs-tag">&lt;/<span class="hljs-name">svg</span>&gt;</span>
                          <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                        <span class="hljs-tag">&lt;/<span class="hljs-name">label</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">label</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 class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-xl font-bold text-[#161515] "</span>&gt;</span>
                      {task.title}
                    <span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-sm font-semibold text-[#42403f] "</span>&gt;</span>
                      {task.description}
                    <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex gap-2 mt-2 text-xs font-bold"</span>&gt;</span>
                      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex items-center "</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">img</span>
                          <span class="hljs-attr">src</span>=<span class="hljs-string">{userImages[index]}</span>
                          <span class="hljs-attr">alt</span>=<span class="hljs-string">""</span>
                          <span class="hljs-attr">className</span>=<span class="hljs-string">"w-10 h-10 rounded-full "</span>
                        /&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span> {task.assignedTo}<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">div</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>
                    <span class="hljs-attr">className</span>=<span class="hljs-string">"p-2 ml-auto rounded-full cursor-pointer hover:bg-red-300"</span>
                    <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> deleteTaskMutation({ id: task.id })}&gt;
                    <span class="hljs-tag">&lt;<span class="hljs-name">FaTrash</span> <span class="hljs-attr">color</span>=<span class="hljs-string">"#545240"</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 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 class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/07/5-Delete-operation-after-delay.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Delete operation after delay</em></p>
<p>These few seconds of inactivity or loading can impact the level of satisfaction users get from your application, which is why we’re going to use Optimistic UI to fix it.</p>
<h3 id="heading-optimistic-crud-ui">Optimistic CRUD UI</h3>
<p>The way this works in practical terms is that, when you perform an action, it immediately adds to your UI state (cache) while the async operation is running in the background.</p>
<p>If the operation is successful, nothing on the UI changes and everything acts like it worked on the first try. But if it fails, the UI state reverts to its previous state and an error is displayed via your toast.</p>
<p>An optimistic UI approach offers a much better user experience than traditional loading messages or spinners. When you see an immediate response after clicking a button, the app feels faster and more responsive, keeping you engaged and satisfied. You can continue interacting with the app seamlessly, without waiting for server confirmations, making the experience smoother and more intuitive.</p>
<p>This immediate feedback reduces your perceived wait time and keeps the interface visually stable, avoiding annoying flickers or sudden changes. Plus, when the app feels this responsive, you're more likely to keep using it and have a positive experience.</p>
<p>On the flip side, loading messages or spinners can interrupt your flow, making the app feel slower and potentially frustrating you.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/07/Group-369-1.png" alt="Image" width="600" height="400" loading="lazy">
<em>Optimistic UI diagram</em></p>
<p>It still sounds a little like gibberish, eh? Well, let’s learn as we go!</p>
<p>In your <code>swrAPI</code> file, create another mutation function. This function takes in two parameters: the new task you want to add and the list of already existing tasks.</p>
<pre><code class="lang-js"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> addTaskMutation = <span class="hljs-keyword">async</span> (newTask, tasks) =&gt; {
  };
</code></pre>
<p>Then it uses your already existing <code>create</code> function to attempt to create a new task. After this, you store the result and return that result in a new array, together with the already existing tasks.</p>
<pre><code class="lang-js"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> addTaskMutation = <span class="hljs-keyword">async</span> (newTask, tasks) =&gt; {
  <span class="hljs-keyword">const</span> addedTask = <span class="hljs-keyword">await</span> addSingleTask(newTask);
  <span class="hljs-keyword">return</span> [...tasks, addedTask].sort(
    <span class="hljs-function">(<span class="hljs-params">a, b</span>) =&gt;</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(b.createdAt) - <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(a.createdAt)
  );
};
</code></pre>
<p>As you would suspect, this function does the same as the previous <code>create</code> function we wrote, but it’s what comes next that we’re after.</p>
<p>Next, create an <code>options</code> function which is responsible for treating the async operation as a synchronous operation and immediately yields a response.</p>
<p>This function also takes some parameters such as:</p>
<ul>
<li><strong><code>optimisticData</code></strong>: which is the new data you want to display immediately.</li>
<li><strong><code>rollbackOnError</code></strong>: which sets the state to the previous one if the request fails.</li>
<li><strong><code>populateCache</code></strong>: which immediately sets this optimistic data in our UI state.</li>
<li><strong><code>revalidate</code></strong>: which lets us enable or disable another fetch after this function runs.</li>
</ul>
<pre><code class="lang-js"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> addTaskOptions = <span class="hljs-function">(<span class="hljs-params">newTask, tasks</span>) =&gt;</span> {
  <span class="hljs-keyword">return</span> {
    <span class="hljs-attr">optimisticData</span>: [...tasks, newTask].sort(
      <span class="hljs-function">(<span class="hljs-params">a, b</span>) =&gt;</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(b.createdAt) - <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(a.createdAt)
    ),
    <span class="hljs-attr">rollbackOnError</span>: <span class="hljs-literal">true</span>,
    <span class="hljs-attr">populateCache</span>: <span class="hljs-literal">true</span>,
    <span class="hljs-attr">revalidate</span>: <span class="hljs-literal">false</span>,
  };
};
</code></pre>
<p>To use this optimistic UI method with a <code>create</code> operation, import both functions into your <code>TaskForm</code>. Both functions need to be wrapped in the <code>mutate</code> function since they’re both attempting to mutate the data.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> {
  addTaskMutation <span class="hljs-keyword">as</span> addSingleTask,
  addTaskOptions,
} <span class="hljs-keyword">from</span> <span class="hljs-string">"./services/swrAPI"</span>;

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

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Taskform</span>(<span class="hljs-params">{ mutate, tasks }</span>) </span>{
  <span class="hljs-keyword">const</span> [title, setTitle] = useState(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> [description, setDescription] = useState(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> [assignedTo, setAssignedTo] = useState(<span class="hljs-string">""</span>);

  <span class="hljs-keyword">const</span> addTaskMutation = <span class="hljs-keyword">async</span> (e) =&gt; {
    e.preventDefault();
    <span class="hljs-keyword">const</span> createdAt = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().toISOString();
    <span class="hljs-keyword">try</span> {

      <span class="hljs-keyword">await</span> mutate(
        addSingleTask(
          {
            title,
            description,
            assignedTo,
            <span class="hljs-attr">completed</span>: <span class="hljs-literal">false</span>,
            createdAt,
          },
          tasks
        ),
        addTaskOptions(
          {
            title,
            description,
            assignedTo,
            <span class="hljs-attr">completed</span>: <span class="hljs-literal">false</span>,
            createdAt,
          },
          tasks
        )
      ); 
     toast.success(<span class="hljs-string">"Task added succesfully."</span>);

    } <span class="hljs-keyword">catch</span> (err) {
      toast.error(<span class="hljs-string">"Failed to add the new task."</span>);
    }
  };
</code></pre>
<p><strong>Note</strong>: The tasks array is passed into the <code>TaskForm</code> via props for this functionality to work.</p>
<p>To see instances where there might be an error, give your functions a 50/50 chance of success or failure, by adding a random condition.</p>
<pre><code class="lang-js"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> addSingleTask = <span class="hljs-keyword">async</span> ({
  title,
  description,
  completed,
  assignedTo,
  createdAt,
}) =&gt; {
  <span class="hljs-keyword">await</span> delay();
  <span class="hljs-keyword">if</span> (<span class="hljs-built_in">Math</span>.random() &lt; <span class="hljs-number">0.5</span>) <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">"Failed to add new task"</span>);
  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> tasksApi.post(tasksUrlEndpoint, {
    title,
    description,
    completed,
    assignedTo,
    createdAt,
  });
  <span class="hljs-keyword">return</span> response.data;
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> updateSingleTask = <span class="hljs-keyword">async</span> (task) =&gt; {
  <span class="hljs-keyword">await</span> delay();
  <span class="hljs-keyword">if</span> (<span class="hljs-built_in">Math</span>.random() &lt; <span class="hljs-number">0.5</span>) <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">"Failed to update task"</span>);
  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> tasksApi.patch(<span class="hljs-string">`<span class="hljs-subst">${tasksUrlEndpoint}</span>/<span class="hljs-subst">${task.id}</span>`</span>, task);
  <span class="hljs-keyword">return</span> response.data;
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> deleteSingleTask = <span class="hljs-keyword">async</span> ({ id }) =&gt; {
  <span class="hljs-keyword">await</span> delay();
  <span class="hljs-keyword">if</span> (<span class="hljs-built_in">Math</span>.random() &lt; <span class="hljs-number">0.5</span>) <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">"Failed to update task"</span>);
  <span class="hljs-keyword">return</span> <span class="hljs-keyword">await</span> tasksApi.delete(<span class="hljs-string">`<span class="hljs-subst">${tasksUrlEndpoint}</span>/<span class="hljs-subst">${id}</span>`</span>, id);
};
</code></pre>
<p>Testing your <code>create</code> endpoint now gives the following result:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/07/6-Optimistic-UI-with-Create-operation.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Optimistic UI with Create operation</em></p>
<p>And voilà! Your app is officially optimistic. It attempts to immediately add the new task to the list even if it fails and gracefully rolls back in the case of an error.</p>
<p>This works similarly for the update operation – starting with the updated <code>update</code> function:</p>
<pre><code class="lang-js"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> updateTaskMutation = <span class="hljs-keyword">async</span> (updatedTask, tasks) =&gt; {
  <span class="hljs-keyword">const</span> updatedTaskResponse = <span class="hljs-keyword">await</span> updateSingleTask(updatedTask);
  <span class="hljs-keyword">return</span> tasks.map(<span class="hljs-function">(<span class="hljs-params">task</span>) =&gt;</span>
    task.id === updatedTask.id ? updatedTaskResponse : task
  );
};
</code></pre>
<p>Then its corresponding <code>options</code> function:</p>
<pre><code class="lang-js"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> updateTaskOptions = <span class="hljs-function">(<span class="hljs-params">updatedTask, tasks</span>) =&gt;</span> {
  <span class="hljs-keyword">return</span> {
    <span class="hljs-attr">optimisticData</span>: tasks.map(<span class="hljs-function">(<span class="hljs-params">task</span>) =&gt;</span>
      task.id === updatedTask.id ? updatedTask : task
    ),
    <span class="hljs-attr">rollbackOnError</span>: <span class="hljs-literal">true</span>,
    <span class="hljs-attr">populateCache</span>: <span class="hljs-literal">true</span>,
    <span class="hljs-attr">revalidate</span>: <span class="hljs-literal">false</span>,
  };
};
</code></pre>
<p>To test this out, import the new <code>updateSingleTask</code> and <code>updateOptions</code> function in your <code>TaskConatiner</code>, and update the handler function.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> updateTaskMutation = <span class="hljs-keyword">async</span> (updatedTask) =&gt; {
    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">await</span> mutate(
        updateSingleTask(updatedTask, tasks),
        updateTaskOptions(updatedTask, tasks)
      );
      toast.success(<span class="hljs-string">"Successfully updated task"</span>);
    } <span class="hljs-keyword">catch</span> (err) {
      toast.error(<span class="hljs-string">"Failed to update the task."</span>);
    }
  };
</code></pre>
<p>Which gives the following result:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/07/7-Optimistic-UI-with-Update-operation---fix-gif.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Optimistic UI with Update operation</em></p>
<p>And finally for the delete action:</p>
<pre><code class="lang-js"><span class="hljs-comment">// Function for deleting a task</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> deleteTaskMutation = <span class="hljs-keyword">async</span> (taskToDelete, tasks) =&gt; {
  <span class="hljs-keyword">await</span> deleteSingleTask(taskToDelete);
  <span class="hljs-keyword">return</span> tasks.filter(<span class="hljs-function">(<span class="hljs-params">task</span>) =&gt;</span> task.id !== taskToDelete.id);
};

<span class="hljs-comment">// Options for deleting a task</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> deleteTaskOptions = <span class="hljs-function">(<span class="hljs-params">taskToDelete, tasks</span>) =&gt;</span> {
  <span class="hljs-keyword">return</span> {
    <span class="hljs-attr">optimisticData</span>: tasks.filter(<span class="hljs-function">(<span class="hljs-params">task</span>) =&gt;</span> task.id !== taskToDelete.id),
    <span class="hljs-attr">rollbackOnError</span>: <span class="hljs-literal">true</span>,
    <span class="hljs-attr">populateCache</span>: <span class="hljs-literal">true</span>,
    <span class="hljs-attr">revalidate</span>: <span class="hljs-literal">false</span>,
  };
};
</code></pre>
<p>Which can be used in the <code>TaskContainer</code> delete handler like so:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> deleteTaskMutation = <span class="hljs-keyword">async</span> ({ id }) =&gt; {
    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">await</span> mutate(
        deleteSingleTask({ id }, tasks),
        deleteTaskOptions({ id }, tasks)
      );
      toast.success(<span class="hljs-string">"Successfully deleted task"</span>);
    } <span class="hljs-keyword">catch</span> (err) {
      toast.error(<span class="hljs-string">"Failed to delete the task."</span>);
    }
  };
</code></pre>
<p>Which gives this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/07/8-Optimistic-UI-with-Delete-operation.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Optimistic UI with Delete operation</em></p>
<h2 id="heading-drawbacks-of-optimistic-ui">Drawbacks of Optimistic UI</h2>
<p>Now you must be thinking, if optimistic UI is so great, why not use it everywhere?</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/07/lighter-hairspray.gif" alt="Image" width="600" height="400" loading="lazy">
<em>lighter hairspray gif</em></p>
<p>Well, like everything, that action turns chaotic without moderation. Here are some reasons why you should use optimistic UI in moderation.</p>
<ol>
<li><strong>Excessive Updates</strong>: Optimistic UI might get a bit carried away with updates, especially if your app's moving faster than your internet connection. Too many updates can slow things down, so it's essential to strike a balance.</li>
<li><strong>Exposing server-side logic</strong>: While offloading all the smarts to your app (like generating unique IDs or checking if that username is already taken) is tempting, remember that your server plays a crucial role too. Letting the front end of your app handle everything can lead to security risks and messy code, so be mindful of where you're putting your logic.</li>
<li><strong>Managing Mishaps:</strong> While Optimistic UI typically expects smooth sailing, life has a way of throwing curveballs. From a sudden internet hiccup to the server taking an unexpected coffee break, glitches can be quite a headache to manage gracefully.</li>
<li><strong>Avoid Rapid Changes</strong>: Imagine adding an item to your shopping cart, and then deciding to remove it before the "add" request even reaches the server. It's like changing your mind at the checkout counter – a bit confusing, right? Rapid changes like these can leave your app disoriented, so it's best to proceed cautiously.</li>
</ol>
<h2 id="heading-ideal-use-cases-for-optimistic-ui">Ideal Use Cases for Optimistic UI</h2>
<p>While optimistic UI may not be the holy grail of state management you were hoping to discover, it does have some good use cases such as:</p>
<ol>
<li><strong>Instant Messaging Apps</strong>: Almost all instant messaging platforms currently use this pattern. Your messages appear instantly in the chat window, even before they're confirmed by the server. This creates a seamless and responsive chatting experience, keeping the conversation flowing effortlessly.</li>
<li><strong>Collaborative Editing Tools</strong>: Whether you're working on a document with colleagues or collaborating on a project with teammates, Optimistic UI ensures that changes are reflected in real time. As you type, edit, or make updates, your changes are immediately visible to others, fostering collaboration and productivity.</li>
<li><strong>Social Media Feeds</strong>: Scroll through your social media feed, and you'll see posts, likes, and comments popping up like magic. Optimistic UI ensures that interactions, such as liking a post or leaving a comment, are reflected instantly, providing a more engaging browsing experience.</li>
<li><strong>E-commerce Websites</strong>: Adding items to your shopping cart, updating quantities, and checking out should feel like a breeze. Optimistic UI speeds up the shopping process by immediately updating your cart and displaying feedback, such as item availability or pricing changes, without delay.</li>
</ol>
<p>For convenience, here are some resources you may need:</p>
<ul>
<li><a target="_blank" href="https://github.com/Daiveedjay/Optimistic-UI-with-SWR/tree/starter">Starter Code</a></li>
<li><a target="_blank" href="https://github.com/Daiveedjay/Optimistic-UI-with-SWR/tree/final">Finished Code</a></li>
</ul>
<p>I'd like to acknowledge <a target="_blank" href="https://x.com/yesdavidgray?t=DlFXltzVgL_iokc_225Fgw&amp;s=08">Dave Gray</a>. It was <a target="_blank" href="https://www.youtube.com/watch?v=6gb6oyO1Tyg">his YouTube video</a> that inspired this article. </p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>As we wrap up our dive into Optimistic UI, it's clear that this technique can be a user experience game-changer. It's the rush of your message popping up instantly or your shopping cart updating in real-time.</p>
<p>Optimistic UI is about speed as well as how it makes users feel – connected, empowered, and delighted. So, next time you click and see the magic unfold, remember: it's not just code...it's the pulse of user happiness (not a Coca-Cola ad 😂). Keep that magic alive in your apps!</p>
<p>Happy coding, and have an optimistic day!</p>
<p><strong>Like my articles?</strong></p>
<p>Feel free to <a target="_blank" href="https://www.buymeacoffee.com/JajaDavid">buy me a coffee here</a>, to keep my brain chugging and provide more articles like this.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/06/coffee-tom.gif" alt="coffee-tom" width="600" height="400" loading="lazy">
<em>Coffee Tom</em></p>
<h3 id="heading-contact-information"><strong>Contact Information</strong></h3>
<p>Want to connect or contact me? Feel free to hit me up on the following:</p>
<ul>
<li>Twitter / X: <a target="_blank" href="https://twitter.com/JajaDavid8">@jajadavid8</a></li>
<li>LinkedIn: <a target="_blank" href="https://www.linkedin.com/in/david-jaja-8084251b4/">David Jaja</a></li>
<li>Email: Jajadavidjid@gmail.com</li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ When to Use NPM Packages – A Guide for Developers ]]>
                </title>
                <description>
                    <![CDATA[ You know when you hit a roadblock while coding and think, "Hey, someone has probably done this before"? That's where npm (Node Package Manager) comes in handy. This huge collection of ready-made code modules created by other developers allows you to ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/when-to-use-npm-packages/</link>
                <guid isPermaLink="false">66bb8925b0d3ac3d7acde3df</guid>
                
                    <category>
                        <![CDATA[ npm ]]>
                    </category>
                
                    <category>
                        <![CDATA[ software development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ David Jaja ]]>
                </dc:creator>
                <pubDate>Mon, 24 Jun 2024 15:59:46 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/06/Article-Image.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>You know when you hit a roadblock while coding and think, "Hey, someone has probably done this before"? That's where npm (Node Package Manager) comes in handy. This huge collection of ready-made code modules created by other developers allows you to plug them into your projects and take advantage of these solutions.</p>
<p>In this article, we’ll talk about npm packages along with their benefits and pitfalls. I'll equip you with the tools and knowledge to help you decide when to use npm packages.</p>
<h2 id="heading-what-well-cover"><strong>What We'll Cover:</strong></h2>
<ol>
<li><a class="post-section-overview" href="#heading-whats-the-deal-with-npm-and-npm-packages">What's the Deal with NPM and NPM Packages?</a></li>
<li><a class="post-section-overview" href="#heading-advantages-of-using-npm-packages">Advantages of using NPM Packages</a></li>
<li><a class="post-section-overview" href="#heading-the-danger-of-over-reliance-on-npm-packages">The Danger of Over-reliance on NPM Packages</a></li>
<li><a class="post-section-overview" href="#heading-striking-a-balance-with-npm-packages">Striking a Balance with NPM Packages</a> </li>
<li><a class="post-section-overview" href="#heading-what-to-consider-when-choosing-an-npm-package">What to Consider When Choosing an NPM Package</a></li>
<li><a class="post-section-overview" href="#heading-efficient-approach-to-using-npm-packages">Efficient Approach to Using npm Packages</a>                                                                   – <a class="post-section-overview" href="#heading-when-to-use-npm-packages">When to Use npm Packages</a><br>– <a class="post-section-overview" href="#heading-when-using-a-package-may-not-be-necessary">When Using a Package May Not Be Necessary</a></li>
<li><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></li>
</ol>
<h2 id="heading-whats-the-deal-with-npm-and-npm-packages">What's the Deal with Npm and Npm Packages?</h2>
<p>Npm, short for <a target="_blank" href="https://www.npmjs.com/">Node Package Manager</a>, plays a crucial role in the JavaScript community. It serves as both a repository and a manager for open-source Node.js packages. </p>
<p>Through npm, developers gain access to many tools, enabling them to install, share, and manage dependencies within their projects.</p>
<p>Think of npm packages as building blocks for coding. They range from simple utilities to elaborate frameworks, streamlining development efforts. Instead of starting from scratch for every challenge, you can leverage these components from your digital toolkit to help accelerate your projects.</p>
<h2 id="heading-advantages-of-using-npm-packages">Advantages of Using NPM Packages</h2>
<p>NPM brings with it a large number of advantages such as:</p>
<p><strong>Efficiency Boost</strong>: Rather than spending hours figuring out a solution from scratch, npm packages offer a shortcut. They're like little time savers that allow you to implement features and functionalities with just a few lines of code.</p>
<p><strong>Wide Range of Options</strong>: From basic utilities to advanced frameworks, there's a package for almost anything. Need to add a slick carousel to your website? There's a package for that. Tired of the peace that code-formatters like Prettier bring and want to embrace violence? You guessed it—there's <a target="_blank" href="https://www.npmjs.com/package/shittier">a package for that</a> too! Heck, <a target="_blank" href="https://www.npmjs.com/package/is-thirteen?activeTab=readme">need to check if a value (number) equals 13</a> 😂? NPM can help. </p>
<p>With npm, the possibilities are virtually endless, giving you access to a world of pre-built solutions at your fingertips.</p>
<p><strong>Community Collaboration</strong>: One of the great things about npm is the strong sense of community it creates. Developers from around the globe actively add to the npm ecosystem by creating and sharing packages. This means you're not just depending on your skills – you're benefiting from the collective knowledge and experience of many developers. </p>
<p>If you run into a problem with a package, you can simply check out forums or GitHub repositories where someone else may have encountered the same issue and can help out. It's like having a team of experienced experts ready to lend a hand whenever you need it.</p>
<p><strong>Modularity and Code Reusability</strong>: NPM packages encourage a modular approach to development, which is like organising your code into neat little building blocks. This makes your codebase more maintainable, scalable, and easier to debug. Plus, it promotes code reusability, allowing you to leverage existing packages in multiple projects.</p>
<p><strong>Streamlined Development Workflow</strong>: With npm packages, you can streamline your development workflow and focus on what you do best—building awesome stuff. </p>
<p>Instead of getting bogged down in the nitty-gritty details of implementation, you can quickly integrate existing solutions and move on to the next task. This allows you to iterate faster, meet deadlines more efficiently, and ultimately deliver better results to your clients or users.</p>
<h2 id="heading-the-danger-of-over-reliance-on-npm-packages">The Danger of Over-reliance on NPM Packages</h2>
<p>So, here's the deal: while npm packages can be like a magical fix for coding difficulties, they also come with some downsides. Let me share a story from my time learning with my mentor, let's call him Hihi.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/06/wink-meme.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Wink meme</em></p>
<p>Hihi was all about building strong coding skills from the ground up. He often said, "<em>Packages are handy shortcuts, but if you rely on them too much, you might end up stuck.</em>" </p>
<p>I remember how he'd challenge me to build UI components like dropdown menus, sliders, animations and so on without using any packages. It was tough, but it taught me a lot about how things work behind the scenes.</p>
<p>Hihi had seen firsthand how relying too much on packages could trip up developers. He'd tell me about people he knew who struggled to implement features when they didn't have their trusty packages to lean on. It wasn't just about being a coding genius—it was about understanding the fundamentals and learning to think outside the box.</p>
<p>And you know what? Hihi was right. Building stuff from scratch pushed me to understand the code and solve my problems when things got tricky.</p>
<h3 id="heading-why-you-shouldnt-overuse-npm-packages">Why You Shouldn't Overuse NPM Packages</h3>
<p><strong>Dependency Overload</strong>: Adding each npm package to your project also means adding its dependencies. This can lead to a mess of dependencies that become tricky to handle and keep up to date. </p>
<p>Plus, updating a package can sometimes cause unexpected issues, potentially breaking your application's functionality.</p>
<p><strong>Security Risks</strong>: Not all npm packages are created equal. Some may contain vulnerabilities or even malicious code (often seen in the terminal right after installing a package), putting your projects at risk. Relying too heavily on packages without vetting them properly can leave your projects vulnerable to attacks.</p>
<p><strong>Maintenance Burden</strong>: When you rely on npm packages for essential functionality, you're at the mercy of the package maintainers. If a package gets deprecated or stops receiving updates, you're left scrambling to find a replacement or fix the issue yourself.</p>
<p><strong>Loss of Creativity</strong>: Over-reliance on npm packages can stifle our creativity as developers. Instead of thinking critically and problem-solving independently, you may default to using packages as a crutch. This can hinder your growth and development as a programmer, limiting your ability to tackle new challenges and innovate.</p>
<p><strong>Increased Bundle Size</strong>: Integrating each npm package into your project adds to the overall bundle size, and depending on various factors, some packages (Looking at you, <a target="_blank" href="https://www.npmjs.com/package/styled-components/v/6.1.8">styled-components</a> 😒😂) can bulk up significantly. </p>
<p>This can pose a notable challenge, particularly if speed and performance are important for your application. Larger bundles may result in sluggish load times, which negatively affect user experience and even your search engine rankings.</p>
<p><strong>Overhead of Unused Code</strong>: NPM packages often come with a lot of extra code that you may not need for your project. This unused code adds unnecessary overhead to your application, bloating the file size and slowing down performance.</p>
<p><strong>Compatibility Concerns</strong>: Mixing and matching npm packages can sometimes lead to compatibility issues, especially when different packages are written in different programming languages or use conflicting versions of dependencies. </p>
<p>For example, if one package is written in JavaScript and another in TypeScript, they may play poorly together, leading to errors and unexpected behaviour.</p>
<h2 id="heading-striking-a-balance-with-npm-packages">Striking a Balance with NPM Packages</h2>
<p>Now hold on a minute, I don’t want you to think that NPM is all bad. NPM packages can be super helpful and you shouldn't fear them.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/06/woah-family-guy.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Rather, I want you to cultivate the rationale behind your decision-making when choosing npm packages.</p>
<p>Choosing the right npm packages can be a bit like navigating a maze—you want to find the shortest, most efficient path to your destination without getting lost along the way. </p>
<p>So how do you balance leveraging the benefits of npm packages and avoiding the potential pitfalls? Let's break it down.</p>
<h3 id="heading-what-to-consider-when-choosing-an-npm-package">What to Consider When Choosing an NPM Package</h3>
<ul>
<li><strong>How Much of the Package You'll Use</strong>: Consider how much of the package you'll use in your project. If you only need one or two features, building those features yourself may be more efficient.</li>
<li><strong>Package Size</strong>: Larger packages contribute to increased bundle size, which can impact performance. Opt for smaller, more lightweight packages whenever possible.</li>
<li><strong>Complexity of Functionality</strong>: Evaluate whether the functionality provided by the package is fairly complex to implement from scratch. If so, using the package may save time and effort.</li>
<li><strong>Project Time Estimate</strong>: Consider the timeline of your project. If you're working on a tight deadline, using npm packages can speed up development and meet project milestones more quickly.</li>
<li><strong>Maintenance and Support</strong>: Prioritize packages with ongoing maintenance and strong community support. Opt for those with dedicated maintainers and an active community, as they are more likely to receive prompt updates and assistance when needed.</li>
<li><strong>Compatibility</strong>: Ensure that the package is compatible with your project's tech stack, including programming languages, frameworks, and dependencies.</li>
</ul>
<p>To better guide you, here’s a flowchart of how your decision-making process can go.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/06/Flowchart-of-decision-making.png" alt="Image" width="600" height="400" loading="lazy">
<em>How to decide which npm packages to use - and whether to use them.</em></p>
<p>As seen in the graph above, each step is built on the next, aiding you in making a sound choice when picking a package.</p>
<h2 id="heading-efficient-approach-to-using-npm-packages">Efficient Approach to Using npm Packages</h2>
<p>While packages can be incredibly useful for streamlining development and adding advanced features, it's important to consider when you should use them and when it might not be necessary.</p>
<h3 id="heading-when-to-use-npm-packages">When to Use npm Packages</h3>
<ul>
<li><strong>Routing</strong>: If your web app needs complex navigation, grabbing a battle-tested routing library like React Router can make your life a lot easier. These packages handle dynamic route matching, nested routes, and more, saving you time and headaches.</li>
<li><strong>Form Validation</strong>: Save yourself the headache of reinventing the validation wheel. To streamline your form validation process, utilize specialized form validation libraries like <a target="_blank" href="https://formik.org/">Formik</a> for React or <a target="_blank" href="https://vee-validate.logaretm.com/v4/">VeeValidate</a> for Vue.js. These libraries ensure consistent validation behavior across your forms, without the hassle of building it from scratch.</li>
<li><strong>Animations</strong>: Want to dazzle your users with smooth and engaging animations? You can use animation libraries like <a target="_blank" href="https://www.framer.com/motion/">Framer Motion</a> or <a target="_blank" href="https://gsap.com/">GreenSock (GSAP)</a>. These libraries provide an array of tools to help you achieve complex animations with minimal effort, whether it's animating components, transitions, or scroll-based effects.</li>
<li><strong>Styling</strong>: When it comes to styling, CSS-in-JS libraries like <a target="_blank" href="https://styled-components.com/">styled-components</a> or <a target="_blank" href="https://emotion.sh/docs/introduction">Emotion</a> can be powerful allies. While they may not be necessary for simple styling needs, they shine in projects requiring dynamic styling, theming, or responsive design. These libraries offer powerful styling capabilities and component-level encapsulation, making styling a breeze.</li>
<li><strong>UI Components</strong>: Building custom UI components from scratch can be time-consuming, especially for complex components like date pickers or data tables. Integrating well-designed UI component libraries such as <a target="_blank" href="https://ui.shadcn.com/">ShadCN</a>, <a target="_blank" href="https://ant.design/">Ant Design</a>, or <a target="_blank" href="https://tailwindcss.com/">Tailwind CSS</a> can accelerate development and ensure a consistent look and feel across your application.</li>
</ul>
<h3 id="heading-when-using-a-package-may-not-be-necessary">When Using a Package May Not Be Necessary</h3>
<ul>
<li><strong>Basic Utility Functions</strong>: For simple utility functions or helper methods, writing them yourself may be more efficient rather than adding an additional dependency. It also keeps your codebase lightweight and avoids unnecessary dependencies.</li>
<li><strong>Custom Business Logic</strong>: If your project requires highly specialized or domain-specific logic, relying on generic npm packages may not be suitable. Building custom solutions tailored to your project's unique requirements can offer greater flexibility and control over functionality.</li>
<li><strong>Performance Optimization</strong>: While npm packages can provide convenient solutions, they may also introduce overhead and impact performance. For performance-critical aspects of your application, consider optimizing code internally rather than relying on external dependencies.</li>
<li><strong>Learning and Skill Development</strong>: Building features from scratch offers valuable opportunities for learning and skill development. Consider tackling certain challenges without relying on packages to deepen your understanding of underlying concepts and enhance your problem-solving abilities.</li>
</ul>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Remember, npm packages are like tools in a toolbox—useful when needed, but not always necessary. </p>
<p>Before reaching for a package, consider whether it aligns with your project's goals and whether you could achieve the same result with a custom solution. </p>
<p>So next time you're tempted to grab a package, pause and ask yourself: "Do I need it? Do I really need it? Do I…?" You get the idea.</p>
<h3 id="heading-like-my-articles">Like my articles?</h3>
<p>Feel free to <a target="_blank" href="https://www.buymeacoffee.com/JajaDavid">buy me a coffee here</a>, to keep my brain chugging and provide more articles like this.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/06/coffee-tom.gif" alt="coffee-tom" width="600" height="400" loading="lazy">
<em>Coffee Tom</em></p>
<h3 id="heading-contact-information"><strong>Contact Information</strong></h3>
<p>Want to connect or contact me? Feel free to hit me up on the following:</p>
<ul>
<li>Twitter / X: <a target="_blank" href="https://twitter.com/JajaDavid8">@jajadavid8</a></li>
<li>LinkedIn: <a target="_blank" href="https://www.linkedin.com/in/david-jaja-8084251b4/">David Jaja</a></li>
<li>Email: Jajadavidjid@gmail.com</li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build a Rating Component with the React Compound Component Pattern ]]>
                </title>
                <description>
                    <![CDATA[ Have you ever watched a captivating movie or used a fantastic product and wanted to share your experience? In today's world, feedback is critical, and ratings are like currency.  Rating systems are everywhere, from the classic star ratings on movie r... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-build-a-rating-component-with-the-react-compound-component-pattern/</link>
                <guid isPermaLink="false">66bb8908a5fd14123a8b49f9</guid>
                
                    <category>
                        <![CDATA[ components ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ David Jaja ]]>
                </dc:creator>
                <pubDate>Mon, 03 Jun 2024 22:03:41 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/06/Group-341.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Have you ever watched a captivating movie or used a fantastic product and wanted to share your experience? In today's world, feedback is critical, and ratings are like currency. </p>
<p>Rating systems are everywhere, from the classic star ratings on movie review websites to the ubiquitous thumbs up/down on streaming platforms. They guide our choices, shape our opinions, and ultimately influence the success of products and services.</p>
<p>In this article, we will create a movie-themed rating component using the Compound Component pattern in React. I'll guide you through structuring the component, managing its state, and designing an interactive user interface that captures the essence of rating.</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>While this article is tailored to be as low-level as possible, having a base understanding of the React compound component pattern is beneficial. </p>
<p>If you don’t have any experience with it, don't worry – I've got you! Just head over to <a target="_blank" href="https://www.freecodecamp.org/news/build-a-dynamic-dropdown-component/">this compound component article</a> where I break it down more extensively. Other prerequisites include.</p>
<ul>
<li>Fundamentals of HTML, CSS, and Tailwind CSS</li>
<li>Fundamentals of JavaScript, React, and React Hooks.</li>
</ul>
<h2 id="heading-what-well-cover"><strong>What We'll Cover:</strong></h2>
<ol>
<li><a class="post-section-overview" href="#heading-understanding-rating-components">Understanding Rating Components</a><br>– <a class="post-section-overview" href="#heading-what-comprises-a-rating-component">What Comprises a Rating Component</a><br>– <a class="post-section-overview" href="#heading-advantages-of-rating-components">Advantages of Rating Component</a></li>
<li><a class="post-section-overview" href="#heading-regular-react-method-1">How to Build a Rating Componen</a>t                                                                                – <a class="post-section-overview" href="#heading-regular-react-method-1">Regular React Method</a><br>– <a class="post-section-overview" href="#heading-compound-component-method">Compound Component Method</a></li>
<li><a class="post-section-overview" href="#heading-how-to-upgrade-the-rating-component">How to Upgrade Rating Component</a></li>
<li><a class="post-section-overview" href="#heading-and-just-for-fun">And just for fun</a></li>
<li><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></li>
</ol>
<h2 id="heading-understanding-rating-components">Understanding Rating Components</h2>
<p>Rating components are an essential part of modern web applications, particularly in contexts where user feedback is critical. These components provide a user-friendly interface for people to express their opinions, often in a quantifiable manner.</p>
<h3 id="heading-what-comprises-a-rating-component">What Comprises a Rating Component?</h3>
<p>A rating component is a UI element that allows users to provide a rating, usually on a fixed scale. Here are the typical elements that make up a rating component:</p>
<ul>
<li><strong>Icons or Symbols</strong>: These are the visual representations of the rating scale. Common examples include stars, hearts, thumbs, or numerical values.</li>
<li><strong>Interactive States</strong>: These components often change appearance based on user interaction, such as hovering or clicking.</li>
<li><strong>Feedback Mechanism</strong>: Some rating components display immediate feedback, such as highlighting the selected icons or showing the rating value.</li>
<li><strong>Accessibility Features</strong>: Ensuring that the component is accessible to all users, including keyboard navigation and screen readers, is crucial.</li>
<li><strong>Custom Feedback</strong>: Some rating components include a text area allowing users to comment. This feedback helps clarify the reasons behind their ratings and enables them to raise any issues they encounter.</li>
</ul>
<h3 id="heading-advantages-of-rating-components">Advantages of Rating Components</h3>
<p>Rating components offer several benefits, both for users and developers:</p>
<ul>
<li><strong>User Engagement</strong>: They make it easy and enjoyable for users to provide feedback, which can increase engagement.</li>
<li><strong>Quantifiable Feedback</strong>: Ratings provide clear, quantifiable data that can be easily analyzed to gauge user satisfaction.</li>
<li><strong>Guiding Decisions</strong>: For other users, ratings help in making informed decisions about movies, products, services, and more.</li>
<li><strong>Improving Products</strong>: For businesses, ratings are invaluable for understanding user preferences and areas for improvement.</li>
</ul>
<h2 id="heading-how-to-build-a-rating-component">How to Build a Rating Component</h2>
<p>I've prepared a GitHub repository with starter files to speed things up. Simply clone <a target="_blank" href="https://github.com/Daiveedjay/Rating-Component">this repo</a> and install the dependencies.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/06/Let-s-get-this-party-started.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Let's get this party started</em></p>
<p>In this section, we'll build a single rating component with regular React, and then rebuild it with the CC pattern.</p>
<h3 id="heading-regular-react-method">Regular React Method</h3>
<p>You’re probably wondering why we’re going through the hassle of first building the component without the component pattern.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/06/woah-peter-griffin.gif" alt="Image" width="600" height="400" loading="lazy">
<em>woah peter griffin</em></p>
<p>Well, while learning the component pattern, I struggled to fully wrap my head around the logic and ended up with a couple of bugs which could have been prevented with better understanding. </p>
<p>To help with this, I found that building a smaller version of the feature before fully implementing the CCP eventually sped up my development process.</p>
<p>To begin, create a <code>RatingComponent</code> and import it into your <code>App</code> component.</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> RatingComponent <span class="hljs-keyword">from</span> <span class="hljs-string">"./RatingComponent"</span>;
<span class="hljs-keyword">import</span> { Toaster } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-hot-toast"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</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">main</span> <span class="hljs-attr">className</span>=<span class="hljs-string">" bg-[#EAF2F8]  gap-4 min-h-[100dvh] flex justify-center items-center flex-col"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Toaster</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-3xl "</span>&gt;</span>My Ratings Component<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">RatingComponent</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span></span>
  );
}
</code></pre>
<p>Then head over to your <code>RatingComponent</code> and add some basic boilerplate to create a standard rating UI.</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { FiStar } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-icons/fi"</span>;
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">RatingComponent</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">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex bg-white items-center justify-between  border border-black rounded-md min-w-[600px]  p-2"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"p-2 text-base font-semibold"</span>&gt;</span>
        Intersteller <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-gray-400 "</span>&gt;</span>(2014)<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">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex gap-4 p-2"</span>&gt;</span>
        {Array.from({ length: 5 }).map((_, index) =&gt; (
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{index}</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex justify-center"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">FiStar</span>
              <span class="hljs-attr">size</span>=<span class="hljs-string">{25}</span>
              <span class="hljs-attr">strokeWidth</span>=<span class="hljs-string">{0}</span>
              <span class="hljs-attr">fill</span>=<span class="hljs-string">{</span>"<span class="hljs-attr">gold</span>"}
              <span class="hljs-attr">cursor</span>=<span class="hljs-string">"pointer"</span>
              <span class="hljs-attr">className</span>=<span class="hljs-string">"star"</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 class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<p>This makes your UI look like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/06/1-Ratings-UI-created.png" alt="Image" width="600" height="400" loading="lazy">
<em>Ratings UI created</em></p>
<p>At the moment, your UI is static and has no way of changing the rating values. To add interactivity, create a state which holds the initial value of the rating.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> [stars, setStarts] = useState(<span class="hljs-number">0</span>);
</code></pre>
<p>Then attach the setting handler to update the value of the stars when you click on a star.</p>
<pre><code class="lang-js">&lt;FiStar
    size={<span class="hljs-number">25</span>}
    strokeWidth={<span class="hljs-number">0</span>}
    fill={<span class="hljs-string">"gold"</span>}
    cursor=<span class="hljs-string">"pointer"</span>
    className=<span class="hljs-string">"star"</span>
    onClick={<span class="hljs-function">() =&gt;</span> setStarts(index + <span class="hljs-number">1</span>)}
 /&gt;
</code></pre>
<p><strong>Note</strong>: We’re adding 1 to the set value since arrays are zero-based.</p>
<p>To confirm the value of the star being set on click, add a dynamic fill value to each star.</p>
<pre><code class="lang-js"> &lt;FiStar
   size={<span class="hljs-number">25</span>}
   strokeWidth={<span class="hljs-number">0</span>}
   fill={index + <span class="hljs-number">1</span> &lt;= stars ? <span class="hljs-string">"gold"</span> : <span class="hljs-string">"#D6DBDF"</span>}
   cursor=<span class="hljs-string">"pointer"</span>
   className=<span class="hljs-string">"star"</span>
   onClick={<span class="hljs-function">() =&gt;</span> setStarts(index + <span class="hljs-number">1</span>)}
/&gt;
</code></pre>
<p>Which yields the following:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/06/testing-the-rating-component-1.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Testing the rating component</em></p>
<p>To further improve the user feedback, we can convert the meaning of each star and display it to them.</p>
<p>Start by creating an array of labels and colours for the stars.</p>
<pre><code class="lang-js"> <span class="hljs-keyword">const</span> ratingData = [
    { <span class="hljs-attr">label</span>: <span class="hljs-string">"Poor"</span>, <span class="hljs-attr">color</span>: <span class="hljs-string">"#E74C3C"</span> },
    { <span class="hljs-attr">label</span>: <span class="hljs-string">"Bad"</span>, <span class="hljs-attr">color</span>: <span class="hljs-string">"#E59866"</span> },
    { <span class="hljs-attr">label</span>: <span class="hljs-string">"Okay"</span>, <span class="hljs-attr">color</span>: <span class="hljs-string">"#F7DC6F"</span> },
    { <span class="hljs-attr">label</span>: <span class="hljs-string">"Good"</span>, <span class="hljs-attr">color</span>: <span class="hljs-string">"#76D7C4"</span> },
    { <span class="hljs-attr">label</span>: <span class="hljs-string">"Great"</span>, <span class="hljs-attr">color</span>: <span class="hljs-string">"#229954"</span> },
  ];
</code></pre>
<p>Then apply this data to reflect whatever the current ratings are.</p>
<pre><code class="lang-js"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">RatingComponent</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [stars, setStarts] = useState(<span class="hljs-number">0</span>);

  <span class="hljs-keyword">const</span> ratingData = [
    { <span class="hljs-attr">label</span>: <span class="hljs-string">"Poor"</span>, <span class="hljs-attr">color</span>: <span class="hljs-string">"#E74C3C"</span> },
    { <span class="hljs-attr">label</span>: <span class="hljs-string">"Bad"</span>, <span class="hljs-attr">color</span>: <span class="hljs-string">"#E59866"</span> },
    { <span class="hljs-attr">label</span>: <span class="hljs-string">"Okay"</span>, <span class="hljs-attr">color</span>: <span class="hljs-string">"#F7DC6F"</span> },
    { <span class="hljs-attr">label</span>: <span class="hljs-string">"Good"</span>, <span class="hljs-attr">color</span>: <span class="hljs-string">"#76D7C4"</span> },
    { <span class="hljs-attr">label</span>: <span class="hljs-string">"Great"</span>, <span class="hljs-attr">color</span>: <span class="hljs-string">"#229954"</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">"flex bg-white items-center justify-between  border border-black rounded-md min-w-[600px]  p-2"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"p-2 text-base font-semibold"</span>&gt;</span>
        Intersteller <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-gray-400 "</span>&gt;</span>(2014)<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">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex gap-4 p-2"</span>&gt;</span>
        {Array.from({ length: 5 }).map((_, index) =&gt; (
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{index}</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex justify-center"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">FiStar</span>
              <span class="hljs-attr">size</span>=<span class="hljs-string">{25}</span>
              <span class="hljs-attr">strokeWidth</span>=<span class="hljs-string">{0}</span>
              <span class="hljs-attr">fill</span>=<span class="hljs-string">{index</span> + <span class="hljs-attr">1</span> &lt;= <span class="hljs-string">stars</span> ? "<span class="hljs-attr">gold</span>" <span class="hljs-attr">:</span> "#<span class="hljs-attr">D6DBDF</span>"}
              <span class="hljs-attr">cursor</span>=<span class="hljs-string">"pointer"</span>
              <span class="hljs-attr">className</span>=<span class="hljs-string">"star"</span>
              <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> setStarts(index + 1)}
            /&gt;
          <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>
      {stars &gt; 0 ? (
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span>
          <span class="hljs-attr">className</span>=<span class="hljs-string">"font-semibold min-w-[60px] p-2"</span>
          <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">color:</span> <span class="hljs-attr">ratingData</span>[<span class="hljs-attr">stars</span> <span class="hljs-attr">-</span> <span class="hljs-attr">1</span>]?<span class="hljs-attr">.color</span> }}&gt;</span>
          {ratingData[stars - 1]?.label}
        <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">"font-semibold text-gray-400"</span>&gt;</span>No ratings yet...<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      )}
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<p>Which gives this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/06/testing-the-rating-component-with-label-cues.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Testing the rating component with label cues</em></p>
<p>And ta-da! Your ratings component is fully functional and every user can effectively use it to drop an accurate review.</p>
<h3 id="heading-compound-component-method">Compound Component Method</h3>
<p>For this method, we’ll take it a step further and create multiple rating components, because if we’re not doing the most, what are we doing? 😌</p>
<p>Start by creating the context for the component.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> RatingContext = createContext();

<span class="hljs-keyword">const</span> MultiRatingsComponent = <span class="hljs-function">(<span class="hljs-params">{
  children,
  ratingsData,

}</span>) =&gt;</span> {
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">RatingContext.Provider</span>
      <span class="hljs-attr">value</span>=<span class="hljs-string">{{</span>
        <span class="hljs-attr">ratingsData</span>,
      }}&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"relative"</span>&gt;</span>{children}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">RatingContext.Provider</span>&gt;</span></span>
  );
};
</code></pre>
<p>Since we’re going to be working with multiple sets of data to create numerous rating components, the structure of the data being passed in would differ.</p>
<pre><code class="lang-js"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</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> multiRatings = [
    { <span class="hljs-attr">name</span>: <span class="hljs-string">"The Dark Knight"</span>, <span class="hljs-attr">year</span>: <span class="hljs-number">2008</span>, <span class="hljs-attr">length</span>: <span class="hljs-number">5</span>, <span class="hljs-attr">rating</span>: <span class="hljs-number">0</span> },
    { <span class="hljs-attr">name</span>: <span class="hljs-string">"Knives Out"</span>, <span class="hljs-attr">year</span>: <span class="hljs-number">2019</span>, <span class="hljs-attr">length</span>: <span class="hljs-number">5</span>, <span class="hljs-attr">rating</span>: <span class="hljs-number">0</span> },
    { <span class="hljs-attr">name</span>: <span class="hljs-string">"Serendipity"</span>, <span class="hljs-attr">year</span>: <span class="hljs-number">2001</span>, <span class="hljs-attr">length</span>: <span class="hljs-number">5</span>, <span class="hljs-attr">rating</span>: <span class="hljs-number">0</span> },
    { <span class="hljs-attr">name</span>: <span class="hljs-string">"The Dressmaker"</span>, <span class="hljs-attr">year</span>: <span class="hljs-number">2015</span>, <span class="hljs-attr">length</span>: <span class="hljs-number">5</span>, <span class="hljs-attr">rating</span>: <span class="hljs-number">0</span> },
    { <span class="hljs-attr">name</span>: <span class="hljs-string">"The Grand Budapest Hotel"</span>, <span class="hljs-attr">year</span>: <span class="hljs-number">2015</span>, <span class="hljs-attr">length</span>: <span class="hljs-number">5</span>, <span class="hljs-attr">rating</span>: <span class="hljs-number">0</span> },
  ];
  <span class="hljs-keyword">const</span> [ratings, setRatings] = useState(multiRatings);

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">main</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-[#EAF2F8] gap-4 min-h-[100vh] flex justify-center items-center flex-col"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Toaster</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-3xl"</span>&gt;</span>My Ratings Component<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">MultiRatingsComponent</span>
        <span class="hljs-attr">ratingsData</span>=<span class="hljs-string">{ratings}</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">MultiRatingsComponent</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span></span>
  );
}
</code></pre>
<p>Next, flesh out the rest of the component required to make our UI look like the single component we created earlier.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> MultiRatingsComponent = <span class="hljs-function">(<span class="hljs-params">{
  children,
  ratingsData,

}</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> [userFeedback, setUserFeedback] = useState([]);
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">RatingContext.Provider</span>
      <span class="hljs-attr">value</span>=<span class="hljs-string">{{</span>
        <span class="hljs-attr">ratingsData</span>,
      }}&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"relative "</span>&gt;</span>{children}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">RatingContext.Provider</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">const</span> Label = <span class="hljs-function">(<span class="hljs-params">{ name, year }</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">"flex flex-col justify-center gap-1 text-base font-semibold min-w-[220px]"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>{name}<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">" text-[12px]  text-[#AAB7B8]"</span>&gt;</span>{year}<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>
  );
};

<span class="hljs-keyword">const</span> RatingsContainer = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> { ratingsData, updateRating } = useContext(RatingContext);

  <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">"min-w-[600px] bg-white rounded-md flex flex-col"</span>&gt;</span>
      {ratingsData &amp;&amp;
        ratingsData.map((singleData, index) =&gt; (
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span>
            <span class="hljs-attr">key</span>=<span class="hljs-string">{index}</span>
            <span class="hljs-attr">className</span>=<span class="hljs-string">"flex items-center px-4 py-6 border-[#f7f8f9] gap-[75px] border-[0.5px]"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">Label</span> <span class="hljs-attr">name</span>=<span class="hljs-string">{singleData.name}</span> <span class="hljs-attr">year</span>=<span class="hljs-string">{singleData.year}</span> /&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex gap-4 "</span>&gt;</span>
              {Array.from({ length: 5 }).map((_, starIndex) =&gt; (
                <span class="hljs-tag">&lt;<span class="hljs-name">RatingIcon</span>
                  <span class="hljs-attr">key</span>=<span class="hljs-string">{starIndex}</span>
                  <span class="hljs-attr">filled</span>=<span class="hljs-string">{starIndex</span> &lt; <span class="hljs-attr">singleData.rating</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 class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">const</span> RatingIcon = <span class="hljs-function">(<span class="hljs-params">{ filled }</span>) =&gt;</span> {
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">FiStar</span>
      <span class="hljs-attr">size</span>=<span class="hljs-string">{25}</span>
      <span class="hljs-attr">strokeWidth</span>=<span class="hljs-string">{0}</span>
      <span class="hljs-attr">fill</span>=<span class="hljs-string">{filled</span> ? "<span class="hljs-attr">gold</span>" <span class="hljs-attr">:</span> "#<span class="hljs-attr">AAB7B8</span>"}
      <span class="hljs-attr">cursor</span>=<span class="hljs-string">"pointer"</span>
      <span class="hljs-attr">className</span>=<span class="hljs-string">"star"</span>
    /&gt;</span></span>
  );
};
</code></pre>
<p>Then assign each component to its parent to form the compound component.</p>
<pre><code class="lang-js">MultiRatingsComponent.Label = Label;
MultiRatingsComponent.RatingsContainer = RatingsContainer;
MultiRatingsComponent.RatingIcon = RatingIcon;
</code></pre>
<p>To see your component UI, nest the <code>RatingsContainer</code> inside its parent (the <code>App</code> component).</p>
<pre><code class="lang-js"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</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> multiRatings = [
    { <span class="hljs-attr">name</span>: <span class="hljs-string">"The Dark Knight"</span>, <span class="hljs-attr">year</span>: <span class="hljs-number">2008</span>, <span class="hljs-attr">length</span>: <span class="hljs-number">5</span>, <span class="hljs-attr">rating</span>: <span class="hljs-number">0</span> },
    { <span class="hljs-attr">name</span>: <span class="hljs-string">"Knives Out"</span>, <span class="hljs-attr">year</span>: <span class="hljs-number">2019</span>, <span class="hljs-attr">length</span>: <span class="hljs-number">5</span>, <span class="hljs-attr">rating</span>: <span class="hljs-number">0</span> },
    { <span class="hljs-attr">name</span>: <span class="hljs-string">"Serendipity"</span>, <span class="hljs-attr">year</span>: <span class="hljs-number">2001</span>, <span class="hljs-attr">length</span>: <span class="hljs-number">5</span>, <span class="hljs-attr">rating</span>: <span class="hljs-number">0</span> },
    { <span class="hljs-attr">name</span>: <span class="hljs-string">"The Dressmaker"</span>, <span class="hljs-attr">year</span>: <span class="hljs-number">2015</span>, <span class="hljs-attr">length</span>: <span class="hljs-number">5</span>, <span class="hljs-attr">rating</span>: <span class="hljs-number">0</span> },
    { <span class="hljs-attr">name</span>: <span class="hljs-string">"The Grand Budapest Hotel"</span>, <span class="hljs-attr">year</span>: <span class="hljs-number">2015</span>, <span class="hljs-attr">length</span>: <span class="hljs-number">5</span>, <span class="hljs-attr">rating</span>: <span class="hljs-number">0</span> },
  ];

  <span class="hljs-keyword">const</span> [ratings, setRatings] = useState(multiRatings);

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">main</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-[#EAF2F8] gap-4 min-h-[100vh] flex justify-center items-center flex-col"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Toaster</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-3xl"</span>&gt;</span>My Ratings Component<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">MultiRatingsComponent</span>
        <span class="hljs-attr">ratingsData</span>=<span class="hljs-string">{ratings}</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">MultiRatingsComponent.RatingsContainer</span> /&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">MultiRatingsComponent</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span></span>
  );
}
</code></pre>
<p>With that, your UI should look like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/06/2-Ratings-UI-with-CC-pattern.png" alt="Image" width="600" height="400" loading="lazy">
<em>Ratings UI with CC pattern</em></p>
<p>To add our previous functionality where we could set ratings, as well as show their meaning via labels, start by creating an update function in the <code>App</code> component.</p>
<pre><code class="lang-js">  <span class="hljs-keyword">const</span> updateRating = <span class="hljs-function">(<span class="hljs-params">index, newRating</span>) =&gt;</span> {
    setRatings(<span class="hljs-function">(<span class="hljs-params">prevRatings</span>) =&gt;</span>
      prevRatings.map(<span class="hljs-function">(<span class="hljs-params">r, i</span>) =&gt;</span> (i === index ? { ...r, <span class="hljs-attr">rating</span>: newRating } : r))
    );
    <span class="hljs-built_in">console</span>.log(ratings);
  };
</code></pre>
<p>This function uses the index of the clicked component to find the particular data, the modifies the rating property based on the star you click on.</p>
<p>To use it, pass it into the <code>MultiRatingsComponent</code> via props, then share it with all its children with its context.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> MultiRatingsComponent = <span class="hljs-function">(<span class="hljs-params">{
  children,
  ratingsData,
  updateRating,
}</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> [userFeedback, setUserFeedback] = useState([]);
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">RatingContext.Provider</span>
      <span class="hljs-attr">value</span>=<span class="hljs-string">{{</span>
        <span class="hljs-attr">ratingsData</span>,
        <span class="hljs-attr">updateRating</span>,
      }}&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"relative "</span>&gt;</span>{children}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">RatingContext.Provider</span>&gt;</span></span>
  );
};
</code></pre>
<p>Then consume that context in <code>RatingsContainer</code>.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> RatingsContainer = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> { ratingsData, updateRating } = useContext(RatingContext);

  <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">"min-w-[600px] bg-white rounded-md flex flex-col"</span>&gt;</span>
      {ratingsData &amp;&amp;
        ratingsData.map((singleData, index) =&gt; (
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span>
            <span class="hljs-attr">key</span>=<span class="hljs-string">{index}</span>
            <span class="hljs-attr">className</span>=<span class="hljs-string">"flex items-center px-4 py-6 border-[#f7f8f9] gap-[75px] border-[0.5px]"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">Label</span> <span class="hljs-attr">name</span>=<span class="hljs-string">{singleData.name}</span> <span class="hljs-attr">year</span>=<span class="hljs-string">{singleData.year}</span> /&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex gap-4 "</span>&gt;</span>
              {Array.from({ length: 5 }).map((_, starIndex) =&gt; (
                <span class="hljs-tag">&lt;<span class="hljs-name">RatingIcon</span>
                  <span class="hljs-attr">key</span>=<span class="hljs-string">{starIndex}</span>
                  <span class="hljs-attr">filled</span>=<span class="hljs-string">{starIndex</span> &lt; <span class="hljs-attr">singleData.rating</span>}
                    <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> updateRating(index, starIndex + 1)}
                /&gt;
              ))}
            <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 class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
};
</code></pre>
<p>Just before you check the UI, create a <code>RatingsLabel</code> component to show the meaning of each star right next to each star.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> RatingLabel = <span class="hljs-function">(<span class="hljs-params">{ ratingValue }</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> ratingLabel = [
    { <span class="hljs-attr">label</span>: <span class="hljs-string">"Poor"</span>, <span class="hljs-attr">color</span>: <span class="hljs-string">"#E74C3C"</span> },
    { <span class="hljs-attr">label</span>: <span class="hljs-string">"Bad"</span>, <span class="hljs-attr">color</span>: <span class="hljs-string">"#E59866"</span> },
    { <span class="hljs-attr">label</span>: <span class="hljs-string">"Okay"</span>, <span class="hljs-attr">color</span>: <span class="hljs-string">"#F7DC6F"</span> },
    { <span class="hljs-attr">label</span>: <span class="hljs-string">"Good"</span>, <span class="hljs-attr">color</span>: <span class="hljs-string">"#76D7C4"</span> },
    { <span class="hljs-attr">label</span>: <span class="hljs-string">"Great"</span>, <span class="hljs-attr">color</span>: <span class="hljs-string">"#229954"</span> },
  ];
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;&gt;</span>
      {ratingValue &gt; 0 ? (
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span>
          <span class="hljs-attr">className</span>=<span class="hljs-string">"font-semibold min-w-[60px] p-2"</span>
          <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">color:</span> <span class="hljs-attr">ratingLabel</span>[<span class="hljs-attr">ratingValue</span> <span class="hljs-attr">-</span> <span class="hljs-attr">1</span>]?<span class="hljs-attr">.color</span> }}&gt;</span>
          {ratingLabel[ratingValue - 1]?.label}
        <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">"font-semibold text-gray-400"</span>&gt;</span>No ratings yet...<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      )}
    <span class="hljs-tag">&lt;/&gt;</span></span>
  );
};

MultiRatingsComponent.RatingLabel = RatingLabel;
</code></pre>
<p>And nest it in the <code>RatingsContainer</code>.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> RatingsContainer = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> { ratingsData, updateRating } = useContext(RatingContext);

  <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">"min-w-[600px] bg-white rounded-md flex flex-col"</span>&gt;</span>
      {ratingsData &amp;&amp;
        ratingsData.map((singleData, index) =&gt; (
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span>
            <span class="hljs-attr">key</span>=<span class="hljs-string">{index}</span>
            <span class="hljs-attr">className</span>=<span class="hljs-string">"flex items-center px-4 py-6 border-[#f7f8f9] gap-[75px] border-[0.5px]"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">Label</span> <span class="hljs-attr">name</span>=<span class="hljs-string">{singleData.name}</span> <span class="hljs-attr">year</span>=<span class="hljs-string">{singleData.year}</span> /&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex gap-4 "</span>&gt;</span>
              {Array.from({ length: 5 }).map((_, starIndex) =&gt; (
                <span class="hljs-tag">&lt;<span class="hljs-name">RatingIcon</span>
                  <span class="hljs-attr">key</span>=<span class="hljs-string">{starIndex}</span>
                  <span class="hljs-attr">filled</span>=<span class="hljs-string">{starIndex</span> &lt; <span class="hljs-attr">singleData.rating</span>}
                  <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> updateRating(index, starIndex + 1)}
                /&gt;
              ))}
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">RatingLabel</span> <span class="hljs-attr">ratingValue</span>=<span class="hljs-string">{singleData.rating}</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>
  );
};
</code></pre>
<p>Drumroll, please…</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/06/testing-the-rating-component-with-CC-pattern-and-label-cues.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Testing the rating component with CC pattern and label cues</em></p>
<p>With this implementation, you can easily have multiple rating bars, and managing each state would be a breeze.</p>
<h2 id="heading-how-to-upgrade-the-rating-component">How to Upgrade the Rating Component</h2>
<p>Alas, there’s one functionality we haven't implemented. No great rating component is complete without a form which allows users to express their opinions past a couple of stars.</p>
<p>To create a comment component, create a form and some state to manage that form.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> Comment = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> [comment, setComment] = useState(<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">"w-full mt-2 "</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"p-2 text-base font-semibold "</span>&gt;</span>Comment<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"relative "</span> <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{(e)</span>=&gt;</span> handleSubmit(e)}&gt;
        <span class="hljs-tag">&lt;<span class="hljs-name">textarea</span>
          <span class="hljs-attr">name</span>=<span class="hljs-string">"comment"</span>
          <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Add a review"</span>
          <span class="hljs-attr">value</span>=<span class="hljs-string">{comment}</span>
          <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setComment(e.target.value)}
          className="w-full p-4 rounded-md resize-none min-h-20"&gt;<span class="hljs-tag">&lt;/<span class="hljs-name">textarea</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"font-semibold absolute -bottom-1/2 right-0 border bg-[#5499C7] transition-all hover:bg-[#21618C] rounded-md py-2 px-4 text-white"</span>&gt;</span>
          Submit
        <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
};

MultiRatingsComponent.Comment = Comment;
</code></pre>
<p>Then create a handler function for that form.</p>
<pre><code class="lang-js">  <span class="hljs-keyword">const</span> handleSubmit = <span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> {
    e.preventDefault();

    <span class="hljs-keyword">if</span> (comment.length &lt; <span class="hljs-number">3</span>) {
      toast.error(<span class="hljs-string">"Please add more text"</span>);
      <span class="hljs-keyword">return</span>;
    }

    <span class="hljs-comment">// Clear the comment input</span>
    setComment(<span class="hljs-string">""</span>);
  };
</code></pre>
<p>To see the comments after a user submits the form, create a state to hold those comments in the parent context.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> MultiRatingsComponent = <span class="hljs-function">(<span class="hljs-params">{
  children,
  ratingsData,
  updateRating,

}</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> [userFeedback, setUserFeedback] = useState([]);
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">RatingContext.Provider</span>
      <span class="hljs-attr">value</span>=<span class="hljs-string">{{</span>
        <span class="hljs-attr">ratingsData</span>,
        <span class="hljs-attr">updateRating</span>,
        <span class="hljs-attr">userFeedback</span>,
        <span class="hljs-attr">setUserFeedback</span>,

      }}&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"relative "</span>&gt;</span>{children}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">RatingContext.Provider</span>&gt;</span></span>
  );
};
</code></pre>
<p>Then consume that context and store the submitted data in the parent context.</p>
<pre><code class="lang-js"> <span class="hljs-keyword">const</span> { userFeedback, setUserFeedback,} =
    useContext(RatingContext);

  <span class="hljs-keyword">const</span> handleSubmit = <span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> {
    e.preventDefault();

    <span class="hljs-keyword">if</span> (comment.length &lt; <span class="hljs-number">3</span>) {
      toast.error(<span class="hljs-string">"Please add more text"</span>);
      <span class="hljs-keyword">return</span>;
    }

    <span class="hljs-comment">// Create a new feedback object</span>
    <span class="hljs-keyword">const</span> newFeedback = { comment };

    <span class="hljs-comment">// Update the userFeedback state</span>
    setUserFeedback([...userFeedback, newFeedback]);

    <span class="hljs-comment">// Clear the comment input</span>
    setComment(<span class="hljs-string">""</span>);
  };
</code></pre>
<p>To view all the comments left by users, create a <code>UserFeedback</code> component like so:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> UserFeedback = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> { userFeedback } = useContext(RatingContext);
  <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">"absolute top-0 px-8 py-2 translate-x-full bg-white rounded-md max-w-[300px] -right-5"</span>&gt;</span>
      {userFeedback.length &gt; 0 ? (
        <span class="hljs-tag">&lt;&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">h3</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mb-2 text-xl font-semibold"</span>&gt;</span>
            Here are what user think
          <span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
            {userFeedback.map((user, index) =&gt; (
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{index}</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"px-2 "</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">h4</span>&gt;</span>
                  {index + 1}.{" "}
                  <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"font-semibold "</span>&gt;</span>{user.name} <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span> --{" "}
                  {user.text}
                <span class="hljs-tag">&lt;/<span class="hljs-name">h4</span>&gt;</span>
              <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;/&gt;</span></span>
      ) : (
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"font-semibold ext-xl"</span>&gt;</span>No user feedback yet...<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span></span>
      )}
    &lt;/div&gt;
  );
};
MultiRatingsComponent.UserFeedback = UserFeedback;
</code></pre>
<p>This component consumes the state holding the user comments and displays them on the screen.</p>
<p>Just before we test it out, I wanted to replicate a fun quirk I notice from Google whenever someone views your docs. They assign a random name to each user and so will we.</p>
<p>Head over to your <code>App</code> component and create this array:</p>
<pre><code class="lang-js"> <span class="hljs-keyword">const</span> randomNames = [
    <span class="hljs-string">"Anonymous Llama"</span>,
    <span class="hljs-string">"Mysterious Moose"</span>,
    <span class="hljs-string">"Stealthy Sloth"</span>,
    <span class="hljs-string">"Phantom Panda"</span>,
    <span class="hljs-string">"Incognito Iguana"</span>,
    <span class="hljs-string">"Unknown Unicorn"</span>,
    <span class="hljs-string">"Enigmatic Elephant"</span>,
    <span class="hljs-string">"Ghostly Giraffe"</span>,
    <span class="hljs-string">"Shadowy Shark"</span>,
    <span class="hljs-string">"Cryptic Cobra"</span>,
    <span class="hljs-string">"Silent Swan"</span>,
    <span class="hljs-string">"Nameless Narwhal"</span>,
    <span class="hljs-string">"Obscure Octopus"</span>,
    <span class="hljs-string">"Unseen Uakari"</span>,
    <span class="hljs-string">"Hidden Hedgehog"</span>,
    <span class="hljs-string">"Masked Macaw"</span>,
    <span class="hljs-string">"Veiled Vulture"</span>,
    <span class="hljs-string">"Concealed Chameleon"</span>,
    <span class="hljs-string">"Covert Cockatoo"</span>,
    <span class="hljs-string">"Invisible Impala"</span>,
  ];
</code></pre>
<p>Then pass it into your <code>MultiRatingsComponent</code> via props.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> MultiRatingsComponent = <span class="hljs-function">(<span class="hljs-params">{
  children,
  ratingsData,
  updateRating,
  randomNames,
}</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> [userFeedback, setUserFeedback] = useState([]);
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">RatingContext.Provider</span>
      <span class="hljs-attr">value</span>=<span class="hljs-string">{{</span>
        <span class="hljs-attr">ratingsData</span>,
        <span class="hljs-attr">updateRating</span>,
        <span class="hljs-attr">userFeedback</span>,
        <span class="hljs-attr">setUserFeedback</span>,
        <span class="hljs-attr">randomNames</span>,
      }}&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"relative "</span>&gt;</span>{children}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">RatingContext.Provider</span>&gt;</span></span>
  );
};
</code></pre>
<p>Finally, modify your form handler function to send a random name with the comment.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> Comment = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> [comment, setComment] = useState(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> { userFeedback, setUserFeedback, randomNames } =
    useContext(RatingContext);

  <span class="hljs-keyword">const</span> handleSubmit = <span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> {
    e.preventDefault();

    <span class="hljs-keyword">if</span> (comment.length &lt; <span class="hljs-number">3</span>) {
      toast.error(<span class="hljs-string">"Please add more text"</span>);
      <span class="hljs-keyword">return</span>;
    }

    <span class="hljs-comment">// Generate a random name between 1 and the length of the array</span>
    <span class="hljs-keyword">const</span> randomName =
      randomNames[<span class="hljs-built_in">Math</span>.floor(<span class="hljs-built_in">Math</span>.random() * randomNames.length)];

    <span class="hljs-comment">// Create a new feedback object</span>
    <span class="hljs-keyword">const</span> newFeedback = { <span class="hljs-attr">name</span>: randomName, comment };

    <span class="hljs-comment">// Update the userFeedback state</span>
    setUserFeedback([...userFeedback, newFeedback]);

    <span class="hljs-comment">// Clear the comment input</span>
    setComment(<span class="hljs-string">""</span>);
  };
</code></pre>
<p>Finally, render the <code>Comment</code> and <code>UserFeedback</code> components in their parent inside the <code>App</code> component.</p>
<pre><code class="lang-js"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</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> multiRatings = [
    { <span class="hljs-attr">name</span>: <span class="hljs-string">"The Dark Knight"</span>, <span class="hljs-attr">year</span>: <span class="hljs-number">2008</span>, <span class="hljs-attr">length</span>: <span class="hljs-number">5</span>, <span class="hljs-attr">rating</span>: <span class="hljs-number">0</span> },
    { <span class="hljs-attr">name</span>: <span class="hljs-string">"Knives Out"</span>, <span class="hljs-attr">year</span>: <span class="hljs-number">2019</span>, <span class="hljs-attr">length</span>: <span class="hljs-number">5</span>, <span class="hljs-attr">rating</span>: <span class="hljs-number">0</span> },
    { <span class="hljs-attr">name</span>: <span class="hljs-string">"Serendipity"</span>, <span class="hljs-attr">year</span>: <span class="hljs-number">2001</span>, <span class="hljs-attr">length</span>: <span class="hljs-number">5</span>, <span class="hljs-attr">rating</span>: <span class="hljs-number">0</span> },
    { <span class="hljs-attr">name</span>: <span class="hljs-string">"The Dressmaker"</span>, <span class="hljs-attr">year</span>: <span class="hljs-number">2015</span>, <span class="hljs-attr">length</span>: <span class="hljs-number">5</span>, <span class="hljs-attr">rating</span>: <span class="hljs-number">0</span> },
    { <span class="hljs-attr">name</span>: <span class="hljs-string">"The Grand Budapest Hotel"</span>, <span class="hljs-attr">year</span>: <span class="hljs-number">2015</span>, <span class="hljs-attr">length</span>: <span class="hljs-number">5</span>, <span class="hljs-attr">rating</span>: <span class="hljs-number">0</span> },
  ];

  <span class="hljs-keyword">const</span> randomNames = [...];

  <span class="hljs-keyword">const</span> [ratings, setRatings] = useState(multiRatings);

  <span class="hljs-keyword">const</span> updateRating = <span class="hljs-function">(<span class="hljs-params">index, newRating</span>) =&gt;</span> {
    setRatings(<span class="hljs-function">(<span class="hljs-params">prevRatings</span>) =&gt;</span>
      prevRatings.map(<span class="hljs-function">(<span class="hljs-params">r, i</span>) =&gt;</span> (i === index ? { ...r, <span class="hljs-attr">rating</span>: newRating } : r))
    );
  };
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">main</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-[#EAF2F8] gap-4 min-h-[100vh] flex justify-center items-center flex-col"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Toaster</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-3xl"</span>&gt;</span>My Ratings Component<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">MultiRatingsComponent</span>
        <span class="hljs-attr">ratingsData</span>=<span class="hljs-string">{ratings}</span>
        <span class="hljs-attr">updateRating</span>=<span class="hljs-string">{updateRating}</span>
        <span class="hljs-attr">randomNames</span>=<span class="hljs-string">{randomNames}</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">MultiRatingsComponent.RatingsContainer</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">MultiRatingsComponent.Comment</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">MultiRatingsComponent.UserFeedback</span> /&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">MultiRatingsComponent</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span></span>
  );
}
</code></pre>
<p>And…Presto!</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/06/testing-the-rating-component-with-CC-pattern--label-cues-and-comments.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Testing the rating component with CC pattern, label cues and comments</em></p>
<p>Your rating component is completed, with the added functionality of comments. ⭐<br>How would you rate the ride throughout this build? 5 stars? 😉</p>
<h3 id="heading-additional-information">Additional Information</h3>
<p>Here are links to all the resources you may need from this article.</p>
<ul>
<li><a target="_blank" href="https://github.com/Daiveedjay/Rating-Component">Starter files</a></li>
<li><a target="_blank" href="https://github.com/Daiveedjay/Rating-Component/tree/Single-Rating-Component">Regular React Pattern</a></li>
<li><a target="_blank" href="https://github.com/Daiveedjay/Rating-Component/tree/Compound-Component-Rating">Compound Component Pattern</a></li>
</ul>
<h3 id="heading-and-just-for-fun">And just for fun...</h3>
<p>Since we built a rating component centered around movies, here are 5 movies I consider to be worth 5 stars in no particular order.</p>
<ul>
<li><a target="_blank" href="https://www.google.com/search?q=The+Grand+Budapest+Hotel&amp;oq=The+Grand+Budapest+Hotel&amp;gs_lcrp=EgZjaHJvbWUyBggAEEUYOTIHCAEQABiPAjIHCAIQABiPAjIGCAMQRRhA0gEHMzUyajBqN6gCALACAA&amp;sourceid=chrome&amp;ie=UTF-8">The Grand Budapest Hotel</a> (Comedy/Crime)</li>
<li><a target="_blank" href="https://www.google.com/search?gs_ssp=eJzj4tVP1zc0TDLPNi5JKzE2YPSSKslIVchNTM_LTMtMTs0rUShOLUvNUzAyMDQDACXhDZw&amp;q=the+magnificent+seven+2016&amp;oq=the+magnifi&amp;gs_lcrp=EgZjaHJvbWUqDAgCEC4YQxiABBiKBTIGCAAQRRg5MgoIARAuGNQCGIAEMgwIAhAuGEMYgAQYigUyBwgDEAAYgAQyBwgEEC4YgAQyCggFEC4Y1AIYgAQyCggGEC4Y1AIYgAQyBwgHEAAYgAQyBwgIEC4YgAQyBwgJEAAYjwLSAQg0NjQxajBqN6gCALACAA&amp;sourceid=chrome&amp;ie=UTF-8">The Magnificent Seven</a> (Western/Action)</li>
<li><a target="_blank" href="https://www.google.com/search?q=django+unchained&amp;sca_esv=616ade3b683ed7c0&amp;sxsrf=ADLYWIK4xUiB8xs1iwXWvE9LfHZsNyCFsg%3A1717326804304&amp;ei=1FNcZqaeEtqyhbIPzYCtwQU&amp;gs_ssp=eJzj4tLP1TdIL88qN0g2YPQSSMlKzEvPVyjNS85IzMxLTQEAlJcKLw&amp;oq=django&amp;gs_lp=Egxnd3Mtd2l6LXNlcnAiBmRqYW5nbyoCCAAyDRAuGIAEGLEDGEMYigUyChAAGIAEGEMYigUyChAuGIAEGEMYigUyDRAAGIAEGLEDGEMYigUyChAAGIAEGEMYigUyChAuGIAEGEMYigUyChAAGIAEGEMYigUyChAAGIAEGBQYhwIyBRAAGIAEMgUQABiABDIoEC4YgAQYsQMYQxiKBRiXBRjcBBjeBBjgBBj0AxjxAxj1Axj2A9gBA0jCHlDHBFiUEXACeAGQAQCYAZgCoAH0C6oBAzItNrgBAcgBAPgBAZgCCKACtwyoAhHCAgoQABiwAxjWBBhHwgINEAAYgAQYsAMYQxiKBcICDhAAGLADGOQCGNYE2AEBwgITEC4YgAQYsAMYQxjIAxiKBdgBAsICBxAjGCcY6gLCAhYQLhiABBhDGLQCGMgDGIoFGOoC2AECwgIKECMYgAQYJxiKBcICBBAjGCfCAhAQLhiABBixAxhDGIMBGIoFwgIIEAAYgAQYsQPCAgQQABgDwgILEAAYgAQYsQMYgwHCAiUQLhiABBhDGIoFGJcFGNwEGN4EGOAEGPQDGPEDGPUDGPYD2AEDwgIFEC4YgATCAigQLhiABBixAxhDGIoFGJcFGNwEGN4EGOAEGPQDGPEDGPUDGPYD2AEDmAMJiAYBkAYTugYGCAEQARgJugYGCAIQARgIugYGCAMQARgUkgcFMi4wLjagB72FAQ&amp;sclient=gws-wiz-serp">Django Unchained</a> (Western/Action)</li>
<li><a target="_blank" href="https://www.google.com/search?q=ford+vs+ferrari&amp;sca_esv=616ade3b683ed7c0&amp;sxsrf=ADLYWIL6hL7o3cnMX0eikkhJDvlhvLACHg%3A1717327001772&amp;ei=mVRcZpjqLr6whbIP-eS7kAw&amp;gs_ssp=eJzj4tVP1zc0TDOrNC5IK6o0YPTiT8svSlEoK1ZISy0qSizKBACjAwqR&amp;oq=ford+vs+fer&amp;gs_lp=Egxnd3Mtd2l6LXNlcnAiC2ZvcmQgdnMgZmVyKgIIADINEC4YgAQYsQMYQxiKBTIFEAAYgAQyBRAAGIAEMgUQABiABDIFEAAYgAQyBRAAGIAEMgUQABiABDIFEAAYgAQyBRAAGIAEMgUQABiABDIoEC4YgAQYsQMYQxiKBRiXBRjcBBjeBBjgBBj0AxjxAxj1Axj2A9gBA0jnMFCGA1jZJHAEeAGQAQCYAY8CoAHRF6oBBjAuMi4xMbgBAcgBAPgBAZgCEqACuiSoAhLCAgoQABiwAxjWBBhHwgINEAAYgAQYsAMYQxiKBcICDhAAGLADGOQCGNYE2AEBwgITEC4YgAQYsAMYQxjIAxiKBdgBAsICBxAjGCcY6gLCAhYQLhiABBhDGLQCGMgDGIoFGOoC2AECwgIZEC4YgAQYQxjUAhi0AhjIAxiKBRjqAtgBAsICChAjGIAEGCcYigXCAgQQIxgnwgIKEC4YgAQYQxiKBcICERAuGIAEGLEDGNEDGIMBGMcBwgIIEAAYgAQYsQPCAgsQABiABBixAxiDAcICChAAGIAEGEMYigXCAhAQABiABBixAxhDGIMBGIoFwgIrEC4YgAQYsQMYQxiKBRiXBRjcBBjeBBjgBBj0AxjxAxj1Axj2Axj3A9gBA8ICDRAAGIAEGLEDGEMYigXCAhAQABiABBixAxhDGMkDGIoFwgILEAAYgAQYkgMYigXCAgoQABiABBgUGIcCmAMKiAYBkAYTugYGCAEQARgJugYGCAIQARgIugYGCAMQARgUkgcKNC4wLjEzLjctMaAH3qsB&amp;sclient=gws-wiz-serp">Ford vs Ferrari</a> (Sports/Action)</li>
<li><a target="_blank" href="https://www.imdb.com/title/tt1375666/">Inception</a> (Action/Sci-fi)</li>
</ul>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In conclusion, crafting a movie-themed rating component using the Compound Component pattern in React is a surefire blockbuster for your projects. This approach enables you to create a sleek, modular, and maintainable codebase. </p>
<p>Mastering this technique ensures your rating system is both functional and ready for the future. Lights, camera, action – may your coding journey dazzle with five-star reviews and standing ovations!</p>
<h3 id="heading-like-my-articles">Like my articles?</h3>
<p>Feel free to <a target="_blank" href="https://www.buymeacoffee.com/JajaDavid">buy me a coffee here</a>, to keep my brain chugging and provide more articles like this.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/06/coffee-tom.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Coffee Tom</em></p>
<h3 id="heading-contact-information">Contact Information</h3>
<p>Want to connect or contact me? Feel free to hit me up on the following:</p>
<ul>
<li>Twitter / X: <a target="_blank" href="https://twitter.com/JajaDavid8">@jajadavid8</a></li>
<li>LinkedIn: <a target="_blank" href="https://www.linkedin.com/in/david-jaja-8084251b4/">David Jaja</a></li>
<li>Email: Jajadavidjid@gmail.com</li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ What is Biophilic Design? How to Reconnect with Nature through Web Design ]]>
                </title>
                <description>
                    <![CDATA[ In a world where we're constantly glued to screens and distracted by digital noise, it's easy to forget about nature.  But here's the exciting part: biophilic design offers a cool solution. Usually, it's all about bringing nature into buildings, but ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/what-is-biophilic-design/</link>
                <guid isPermaLink="false">66bb89232108ff2ab9af166f</guid>
                
                    <category>
                        <![CDATA[ Web Design ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ David Jaja ]]>
                </dc:creator>
                <pubDate>Tue, 23 Apr 2024 18:28:38 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/04/Article-Cover-1.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In a world where we're constantly glued to screens and distracted by digital noise, it's easy to forget about nature. </p>
<p>But here's the exciting part: biophilic design offers a cool solution. Usually, it's all about bringing nature into buildings, but now nature is branching out into web design as well.</p>
<p>In this article, we'll explore why we feel disconnected from nature and how biophilic design can help fix that, even in the digital world.</p>
<h2 id="heading-what-is-biophilic-design">What is Biophilic Design?</h2>
<p>Well, it's all about bringing nature back into our lives, whether it's at home, in the office, or wherever we hang out. </p>
<p>It's not just about making things look pretty – it's about making us feel good by reconnecting us with the great outdoors.</p>
<h3 id="heading-history-of-biophilic-design">History of Biophilic Design</h3>
<p>Biophilic design, stemming from the Greek words "bios" (life) and "philia" (love), is all about our natural connection to the world around us. It has its roots in architecture and building design, where people realised that bringing elements of nature into our spaces makes us feel better.</p>
<p>This design approach mimics nature's patterns and includes views of trees and natural light. It's a way of making our homes and workplaces feel more like the outdoors.</p>
<p><img src="https://lh7-us.googleusercontent.com/AL3lORAbV4kKYN94RLG_GCBD3dH0OJtS6V5NtitRfCrPixCweHYZgdzSgwBeUykwhHwkAo-A7gkxCDCBU0uFGoOFleD-kvZ7YVaRvOd1SFT_3Y6SfYuG8bE0MP-W8p75r1stRhiZualfNKTlj_h-TC0" alt="Image" width="1024" height="1024" loading="lazy">
<em>Biophilic Design in Architecture</em></p>
<p>As cities grow and technology becomes more important, we spend less time in nature. That's why biophilic design is so important. It's not just for buildings – it's also being used in things like website design to remind us of our love for nature.</p>
<p>So, whether it's in a physical space or online, biophilic design helps us remember how much we need nature for our happiness and well-being.</p>
<h2 id="heading-the-problem-understanding-our-distance-from-nature">The Problem: Understanding Our Distance from Nature</h2>
<h3 id="heading-how-screens-shape-our-lives">How Screens Shape Our Lives</h3>
<p>You know how it is these days – screens are everywhere, right? From our smartphones and tablets to laptops and TVs, they've become like companions, keeping us hooked for hours. </p>
<p>Sometimes it feels like we're living in a whole different world, one that's all digital and disconnected from nature.</p>
<p>Ever found yourself mindlessly scrolling through social media or binge-watching shows, losing track of time? It's what some call "zombie-scrolling" – we've all been there. 😌</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/Endless-Scrolling.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Endless Scrolling</em></p>
<h3 id="heading-lost-in-the-digital-world-wheres-nature">Lost in the Digital World: Where's Nature?</h3>
<p>We're all guilty of getting sucked into the digital vortex. Whether it's getting lost in Netflix marathons, being glued to our work screens or endless scrolling through Insta… (Let’s be serious, it’s Twitter 😂), our attention rarely strays from the virtual realm. And the more we dive into digital content, the further we drift from the great outdoors. </p>
<p>It's like we're building this invisible wall between ourselves and nature without even realizing it.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/Tweet-it.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Tweet it</em></p>
<h3 id="heading-were-missing-out-on-natures-charms">We're Missing Out on Nature's Charms</h3>
<p>With our lives becoming more and more centered around screens, outdoor adventures seem to be a thing of the past. Many of us spend our days cooped up indoors, surrounded by artificial lights and controlled temperatures. It's like we've forgotten what it feels like <em>actually to touch grass</em> or feel the sun on our faces. There's just not much incentive to step outside and soak in the beauty of nature anymore.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/Touch-grass.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<h3 id="heading-but-were-often-unaware-of-the-disconnect">But We're Often Unaware of the Disconnect</h3>
<p>Here's the thing: Many of us don't even realize how far we've drifted from nature. We're so caught up in the digital world that we hardly think about how it's affecting us and our connection to nature. It's like this subtle but important change that sneaks up on us until we pause and reflect on it.</p>
<p>And here's the kicker: this disconnection isn't just about not enjoying nature's beauty. It's also messing with our health. </p>
<p><a target="_blank" href="https://www.who.int/news-room/fact-sheets/detail/physical-activity">Research shows</a> that spending too much time indoors and not enough time outdoors can cause issues like obesity, depression, and not getting enough vitamin D. Lack of physical activity is a big deal, contributing to millions of deaths every year worldwide. </p>
<p>So, while binge-watching shows or scrolling through social media all day might seem harmless, it's impacting our health and well-being in a big way.</p>
<h2 id="heading-the-harmful-effects-of-a-disconnect-from-nature">The Harmful Effects of a Disconnect from Nature</h2>
<p>As we've seen, our increasing immersion in the digital world comes with consequences beyond just missing out on the joys of nature. This disconnect has profound effects on our health and well-being, impacting us in ways we might not even realize.</p>
<ul>
<li><strong>Mental Health Struggles</strong>: Spending excessive time indoors and away from nature has been linked to higher rates of depression, anxiety, and stress. Without the calming influence of natural environments, our mental health can suffer, leaving us feeling more isolated and disconnected from the world around us.</li>
<li><strong>Physical Health Risks</strong>: Being too sedentary, especially with too much screen time, poses serious risks to our physical health. Conditions like obesity, cardiovascular disease, and diabetes are just some of the issues linked to not being active enough and spending too much time indoors. Our bodies thrive on movement and natural light, and depriving them of these essentials can take a toll on our health.</li>
<li><strong>Vitamin D Deficiency</strong>: Not getting enough sunlight indoors means missing out on vital nutrients like vitamin D, essential for bone health, immune function, and mood regulation. Without sufficient sunlight exposure, we become more prone to deficiencies that can affect our overall health in various ways.</li>
<li><strong>Disconnect from Reality</strong>: As we go deeper into the digital space, we risk losing touch with reality. This gradual disconnection from the natural world means we miss out on the sights, sounds, and sensations that keep us grounded. Ultimately, this disconnect can leave us feeling adrift and disconnected from both ourselves and the world around us.</li>
</ul>
<h2 id="heading-biophilic-elements-in-web-design">Biophilic Elements in Web Design</h2>
<p>Let's talk bout how you can incorporate bits of nature into your website design to help bring the outdoors in and reconnect with the natural world.</p>
<h3 id="heading-natural-forms-and-patterns">Natural Forms and Patterns</h3>
<p>Integrating organic shapes, textures, and patterns reminiscent of nature is key. In web design, this means crafting interfaces that mirror the fluidity and diversity of the natural world.</p>
<p>For example, the UI below utilizes a hanging flower pattern to represent a flower shop, embracing the beauty of nature in its design (<a target="_blank" href="https://dribbble.com/shots/17272076-Floristry-and-decor-studio-Website">reference</a>).</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/01-Floral-website-1.png" alt="Image" width="600" height="400" loading="lazy">
<em>Floral Website</em></p>
<h3 id="heading-natural-materials-and-textures">Natural Materials and Textures</h3>
<p>Incorporating natural materials and textures is crucial for creating a warm and inviting digital environment. Just like in physical spaces, using elements that mimic natural materials can evoke a sense of comfort and connection. </p>
<p>For instance, the UI below shapes the landing page of a woodworking company, resembling components of a furniture piece. This use of imagery mimics the texture and warmth of wood, enhancing the user experience and bringing the outdoors to your screen (<a target="_blank" href="https://dribbble.com/shots/18785612-Selling-decorative-wooden-home-products">reference</a>).</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/02-Wood-Website.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Woodworking Website</em></p>
<h3 id="heading-natural-light-and-views">Natural Light and Views</h3>
<p>Natural light is crucial in biophilic design for creating visually appealing spaces that promote well-being. Similarly, in web design, incorporating light and outdoor views enhances the user experience, fostering a sense of openness and connection to nature. </p>
<p>Maximizing natural light in web layouts involves creating airy designs with ample white space to let light in. Incorporating images or animations of outdoor scenes, like lush landscapes or serene water bodies, deepens the connection to nature, infusing websites with tranquillity and wonder. </p>
<p>For example, the UI below uses real images of nature to brighten up the webpage, harnessing natural light to enhance the user experience (r<a target="_blank" href="https://dribbble.com/shots/23220749-LeafLife-Garden-Landscape-Design-Website-UI-Figma-Template">eference</a>).</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/04-Landscape-website.png" alt="Image" width="600" height="400" loading="lazy">
<em>Landscape Website</em></p>
<h3 id="heading-biophilic-colors">Biophilic Colors</h3>
<p>Colours play a significant role in shaping the mood and user experience. Incorporating colours inspired by nature can cultivate a soothing atmosphere, reinforcing the connection between users and the natural world. </p>
<p>Choosing nature-inspired colours such as earth tones, greens, and blues evokes feelings of tranquillity, vitality, and serenity. These hues, commonly found in natural landscapes, can evoke positive emotions in users.</p>
<p>For instance, the UI below utilizes shades of green to convey a sense of freshness and health associated with the company's food offerings. This use of colour triggers positive associations with nature, enhancing the overall user experience (<a target="_blank" href="https://dribbble.com/shots/23951260-Gardening-Landscaping-website">reference</a>).</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/05-Vegitation-Website.png" alt="Image" width="600" height="400" loading="lazy">
<em>Vegetation Website</em></p>
<h3 id="heading-living-systems-and-biomimicry">Living Systems and Biomimicry</h3>
<p>Biomimicry, mimicking natural processes in design, provides rich inspiration for creating efficient, sustainable, and user-friendly solutions. This involves drawing from natural ecosystems to guide website functionality and navigation. </p>
<p>Emulating natural systems in website design can lead to intuitive user experiences that mirror the adaptability of the natural world. By studying living systems, designers can apply these principles to digital interfaces, enhancing usability and engagement.</p>
<p>For example, the UI below incorporates elements of human anatomy to communicate the company's purpose effectively. This biomimetic approach helps users intuitively understand the company's offerings, enhancing the overall user experience (<a target="_blank" href="https://dribbble.com/shots/20365657-The-Landing-Page-for-the-BioAge-Website">reference</a>).</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/06---Biomimicry-website.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Biomimicry Website</em></p>
<h2 id="heading-benefits-of-biophilic-web-design">Benefits of Biophilic Web Design</h2>
<p>Biophilic web design offers a multitude of benefits that extend beyond mere aesthetics.</p>
<ul>
<li><strong>Enhanced User Experience</strong>: Biophilic elements have the power to evoke positive emotions and create a more engaging user experience. Natural forms, colors, and textures can resonate with users on a subconscious level, fostering a sense of comfort, connection, and delight as they interact with the website.</li>
<li><strong>Improved Well-being</strong>: Exposure to nature, even in digital form, has been shown to reduce stress and enhance cognitive function. By immersing users in environments reminiscent of the natural world, biophilic web design can create digital spaces that promote relaxation, focus, and overall well-being.</li>
<li><strong>Differentiation and Brand Identity</strong>: Incorporating biophilic design can set a website apart from competitors and communicate values of sustainability and connection to the natural world. By aligning with themes of environmental stewardship and holistic living, brands can differentiate themselves and forge deeper connections with environmentally conscious consumers.</li>
<li><strong>Increased User Engagement</strong>:  When websites offer a visually appealing and calming experience, users are more inclined to stick around. By crafting digital environments that mirror the tranquillity and beauty of nature, designers can captivate users' attention, prompting them to explore, interact, and come back for more.</li>
</ul>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/Minion-Kiss.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Minion Kiss</em></p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>As we wrap up our exploration of biophilic design in web design, remember this: while screens can be captivating, don't forget to reconnect with nature. Biophilic design isn't just about aesthetics – it's about infusing digital spaces with the serenity of the outdoors.</p>
<p>And hey, here's a friendly question: Have you touched some grass today 😒? It might be just the digital detox your soul needs. Step away from the screen and immerse yourself in the beauty of the natural world. Your mind, body, and spirit will thank you.</p>
<h3 id="heading-contact-information">Contact Information</h3>
<p>Want to connect or contact me? Feel free to hit me up on the following:</p>
<ul>
<li>Twitter / X: <a target="_blank" href="https://twitter.com/JajaDavid8">@jajadavid8</a></li>
<li>LinkedIn: <a target="_blank" href="https://www.linkedin.com/in/david-jaja-8084251b4/">David Jaja</a></li>
<li>Email: Jajadavidjid@gmail.com</li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build a Dynamic Dropdown Component in React – React Compound Component Pattern Explained ]]>
                </title>
                <description>
                    <![CDATA[ Dropdowns have been an important part of websites and apps for a long time. They're an unsung heros of user interactions, silently facilitating countless actions and decisions with just a click or tap.  You probably encountered one today, whether it ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/build-a-dynamic-dropdown-component/</link>
                <guid isPermaLink="false">66bb88f7e32cc52292637d1f</guid>
                
                    <category>
                        <![CDATA[ projects ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ David Jaja ]]>
                </dc:creator>
                <pubDate>Wed, 17 Apr 2024 19:21:03 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/04/Article-Cover.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Dropdowns have been an important part of websites and apps for a long time. They're an unsung heros of user interactions, silently facilitating countless actions and decisions with just a click or tap. </p>
<p>You probably encountered one today, whether it was selecting a category on your favourite online store or choosing your birthdate on a registration form.</p>
<p>But what if I told you that there's a secret ingredient that can elevate your dropdowns from mundane to magnificent?</p>
<p>Join me as I dissect the mysteries of the compound component pattern and harness its abilities to build a dynamic dropdown component.</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<ul>
<li>Fundamentals of HTML, CSS and Tailwind CSS</li>
<li>Fundamentals of React and React Hooks.</li>
</ul>
<h2 id="heading-what-well-cover">What We'll Cover:</h2>
<ol>
<li><a class="post-section-overview" href="#heading-understanding-dropdown-components">Understanding Dropdown Components</a></li>
<li><a class="post-section-overview" href="#heading-understanding-compound-components">Understanding Compound Components</a></li>
<li><a class="post-section-overview" href="#heading-how-to-build-the-dropdown-component">How to Build the Dropdown Component</a><br>– <a class="post-section-overview" href="#heading-regular-functional-react-method">Regular Functional React Method</a><br>– <a class="post-section-overview" href="#heading-the-compound-component-pattern-method">The Compound Component Pattern Method</a></li>
<li><a class="post-section-overview" href="#heading-comparison-between-the-regular-and-the-compound-component-method">Comparison between the Regular and the Compound Component Method</a></li>
<li><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></li>
</ol>
<h2 id="heading-understanding-dropdown-components">Understanding Dropdown Components</h2>
<p>Dropdown components play a pivotal role in user interface design, functioning as interactive menus that empower users to make selections from a list of options. Typically, they comprise of a clickable area that, upon activation, unveils a roster of choices for the user to make a selection from.</p>
<p>The operation of a dropdown component is straightforward: when a user engages with it—often through clicking or tapping—the dropdown expands, showing the available options.</p>
<p>Subsequently, the user can opt for one of these choices, which is then either shown within the dropdown itself or utilized to update a related field or element in the interface.</p>
<p>Dropdown components provide a clean and efficient method to present a variety of choices to users, rendering them well-suited for scenarios where multiple options need to be accessible while maintaining a tidy interface.</p>
<p>Dropdowns also serve purposes such as:</p>
<ul>
<li><strong>Navigation Aid</strong>: Acting as navigational aids, dropdowns help users move through websites by providing menus to jump to different sections or pages.</li>
<li><strong>Form Inputs</strong>: Simplifying data entry, dropdowns present users with predefined options for selection, such as choosing a country, date of birth, or preferred language during account registration.</li>
<li><strong>Filters</strong>: In e-commerce platforms, dropdowns enable shoppers to refine their search results by selecting options like product categories, price ranges, or brands.</li>
<li><strong>Menu Selectors</strong>: Commonly used on restaurant websites, dropdowns display menus or allow users to choose a cuisine type, facilitating easy exploration and selection of dining options.</li>
<li><strong>Data Presentation</strong>: Dropdowns can organize and present data effectively, allowing users to filter information by criteria such as date range, geographic region, or product category in dashboards or analytics tools.</li>
</ul>
<p>An example of dropdown components can be seen here:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/01-Showing-Dropdown-Demo.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Showing Dropdown Demo</em></p>
<p><strong>Or on <a target="_blank" href="https://semantic-ui.com/modules/dropdown.html">Semantic UI’s page</a>.</strong></p>
<h2 id="heading-understanding-compound-components">Understanding Compound Components</h2>
<p>The compound component pattern is like building with LEGO blocks: you assemble smaller pieces to create something bigger and more complex. In React, it's a clever way of designing components from several smaller parts that work together seamlessly.</p>
<p>Imagine that you're building a dropdown menu. Instead of creating one monolithic component that handles everything, you break it down into smaller, reusable pieces. You might have one component for the dropdown button, another for the list of options, and yet another for handling the state and interaction logic.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/01-Compound-Component-Illustration.png" alt="Image" width="600" height="400" loading="lazy">
<em>Compound Component Illustration</em></p>
<p>Here's where it gets interesting: these smaller components communicate through a shared context. Context is like a messenger that carries information from one component to another without needing to pass it down through every level of the component tree. </p>
<p>It's a powerful tool that simplifies the process of sharing data between components, especially when they're deeply nested.</p>
<p>Now, why is this pattern so beneficial?</p>
<ul>
<li>First off, it improves readability. By breaking down a complex component into smaller, more focused pieces, the code becomes easier to understand and maintain. Each component has a clear responsibility, making it easier to debug and update.</li>
<li>Secondly, compound components enhance maintainability. Since each piece of the component handles a specific task, making changes or adding new features becomes much simpler. You can modify one part of the component without affecting the others, reducing the risk of introducing bugs.</li>
<li>Finally, compound components provide great flexibility. You can combine different parts to make special versions of the component without having to rewrite any code. This makes it easier to adjust the component for different purposes and design requirements.</li>
</ul>
<p>So, while the idea of using context to build UI components may seem unusual at first, it's a clever way of creating dynamic and reusable components that empower developers to build exceptional user experiences.</p>
<p>In the next section, we'll dive deeper into how context is used to bring compound components to life.</p>
<h2 id="heading-how-to-build-the-dropdown-component">How to Build the Dropdown Component</h2>
<p>I've prepared a GitHub repository with starter files to speed things up. Simply clone <a target="_blank" href="https://github.com/Daiveedjay/React-Dropdown-Component/tree/Starter">this repo</a> and install the dependencies.</p>
<p>In this section, we'll build a dropdown component using regular functional React, then compare it with the CC pattern to grasp the difference fully. PS: you'd like the compound component pattern. 😁</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/02-Oh-fo-sho-meme.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Oh Fo sho Snoop Dogg gif</em></p>
<h3 id="heading-regular-functional-react-method">Regular Functional React Method</h3>
<p>We'll start by creating the basic structure of our dropdown component. This will involve setting up the main dropdown container, the button to trigger the dropdown, and the list of options.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> Dropdown = <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>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mt-4"</span>&gt;</span>Assign user(s) to as task:<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>

      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"  px-4 w-full py-2 flex items-center justify-between  rounded border border-[#828FA340] hover:border-primary cursor-pointer relative "</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"block"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">FiChevronDown</span> <span class="hljs-attr">color</span>=<span class="hljs-string">"#635FC7"</span> <span class="hljs-attr">size</span>=<span class="hljs-string">{24}</span> /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
      <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>
  );
};
</code></pre>
<p>Which gives:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/02-Dropdown-button-rendered.png" alt="Image" width="600" height="400" loading="lazy">
<em>Dropdown button rendered</em></p>
<p>Then pass in the users array into the dropdown to create a list of users.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> Dropdown = <span class="hljs-function">(<span class="hljs-params">{ usersArray }</span>) =&gt;</span> {
  <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">label</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mt-4"</span>&gt;</span>Assign user(s) to as task:<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>

      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"  px-4 w-full py-2 flex items-center justify-between  rounded border border-[#828FA340] hover:border-primary cursor-pointer relative "</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"block"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">FiChevronDown</span> <span class="hljs-attr">color</span>=<span class="hljs-string">"#635FC7"</span> <span class="hljs-attr">size</span>=<span class="hljs-string">{24}</span> /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
        {
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"absolute bottom-full translate-x-9  left-full translate-y-full rounded bg-[#20212c] w-max"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex flex-col p-2"</span>&gt;</span>
              {usersArray.map((user) =&gt; (
                <span class="hljs-tag">&lt;<span class="hljs-name">li</span>
                  <span class="hljs-attr">key</span>=<span class="hljs-string">{user.id}</span>
                  <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">flex</span> <span class="hljs-attr">items-center</span> <span class="hljs-attr">gap-2</span> <span class="hljs-attr">p-4</span> <span class="hljs-attr">hover:bg-</span>[#<span class="hljs-attr">2b2c37</span>] <span class="hljs-attr">rounded</span> <span class="hljs-attr">transition-all</span> <span class="hljs-attr">duration-200</span> `}&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">img</span>
                    <span class="hljs-attr">className</span>=<span class="hljs-string">"w-6 h-6 "</span>
                    <span class="hljs-attr">src</span>=<span class="hljs-string">{user.imgUrl}</span>
                    <span class="hljs-attr">alt</span>=<span class="hljs-string">{</span>`${<span class="hljs-attr">user.name</span>} <span class="hljs-attr">image</span>`}
                  /&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>{user.name}<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                <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>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
};
</code></pre>
<p>Which gives:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/03-Dropdown-list-rendered.png" alt="Image" width="600" height="400" loading="lazy">
<em>Dropdown list rendered</em></p>
<p>At the moment, your dropdown list is showing by default. To add the toggle behavior, create a state for its visibility.</p>
<pre><code class="lang-jsx"> <span class="hljs-keyword">const</span> [isDropdownOpen, setIsDropdownOpen] = useState(<span class="hljs-literal">false</span>);
</code></pre>
<p>Then pass down both as props to the <code>Dropdown</code> component.</p>
<pre><code class="lang-jsx">&lt;Dropdown
 usersArray={usersArray}
 isDropdownOpen={isDropdownOpen}
 setIsDropdownOpen={setIsDropdownOpen}
 /&gt;
</code></pre>
<p>Before you see the result, attach a toggle function that changes the dropdown state to true to the dropdown button.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> toggleDropdown = <span class="hljs-function">() =&gt;</span> {
    setIsDropdownOpen(<span class="hljs-literal">true</span>);
};
</code></pre>
<p>Your dropdown component should now look like this:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> Dropdown = <span class="hljs-function">(<span class="hljs-params">{ usersArray, setIsDropdownOpen, isDropdownOpen }</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> toggleDropdown = <span class="hljs-function">() =&gt;</span> {
    setIsDropdownOpen(<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>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mt-4"</span>&gt;</span>Assign user(s) to as task:<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>

      <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
        <span class="hljs-attr">className</span>=<span class="hljs-string">"  px-4 w-full py-2 flex items-center justify-between  rounded border border-[#828FA340] hover:border-primary cursor-pointer relative "</span>
        // <span class="hljs-attr">Function</span> <span class="hljs-attr">to</span> <span class="hljs-attr">show</span> <span class="hljs-attr">the</span> <span class="hljs-attr">dropdown</span> <span class="hljs-attr">on</span> <span class="hljs-attr">click</span>
        <span class="hljs-attr">onClick</span>=<span class="hljs-string">{toggleDropdown}</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"block"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">FiChevronDown</span> <span class="hljs-attr">color</span>=<span class="hljs-string">"#635FC7"</span> <span class="hljs-attr">size</span>=<span class="hljs-string">{24}</span> /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
      // Conditionally rendering your dropdown list
        {isDropdownOpen &amp;&amp; (
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"absolute bottom-full translate-x-9  left-full translate-y-full rounded bg-[#20212c] w-max"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex flex-col p-2"</span>&gt;</span>
              {usersArray.map((user) =&gt; (
                <span class="hljs-tag">&lt;<span class="hljs-name">li</span>
                  <span class="hljs-attr">key</span>=<span class="hljs-string">{user.id}</span>
                  <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">flex</span> <span class="hljs-attr">items-center</span> <span class="hljs-attr">gap-2</span> <span class="hljs-attr">p-4</span> <span class="hljs-attr">hover:bg-</span>[#<span class="hljs-attr">2b2c37</span>] <span class="hljs-attr">rounded</span> <span class="hljs-attr">transition-all</span> <span class="hljs-attr">duration-200</span> `}&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">img</span>
                    <span class="hljs-attr">className</span>=<span class="hljs-string">"w-6 h-6 "</span>
                    <span class="hljs-attr">src</span>=<span class="hljs-string">{user.imgUrl}</span>
                    <span class="hljs-attr">alt</span>=<span class="hljs-string">{</span>`${<span class="hljs-attr">user.name</span>} <span class="hljs-attr">image</span>`}
                  /&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>{user.name}<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                <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>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
};
</code></pre>
<p>Your dropdown now behaves like so:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/03-Dropdown-with-list-conditionally-rendering.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Dropdown with list conditionally rendering</em></p>
<p>I know you’ve noticed your dropdown only opens, but doesn’t close. Don’t worry, we’d fix that later in a much cleaner way. 😉</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/04-Trust-the-process.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Trust the process</em></p>
<p>Next up, let’s create a way to assign users to the task. Start by creating a state to store the assigned users in the <code>App</code> component.</p>
<pre><code class="lang-jsx"> <span class="hljs-keyword">const</span> [assignedList, setAssignedList] = useState([]);
</code></pre>
<p>Then pass in the values as props to the <code>Dropdown</code> component.</p>
<pre><code class="lang-jsx">&lt;Dropdown
  usersArray={usersArray}
  isDropdownOpen={isDropdownOpen}
  setIsDropdownOpen={setIsDropdownOpen}
  assignedList={assignedList}
  setAssignedList={setAssignedList}
/&gt;
</code></pre>
<p>To assign users to the task, create a handler function which first checks if the user you're trying to add is already in the array, adds them if they're not, and removes them if they are.</p>
<pre><code class="lang-jsx">  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handleAssign</span>(<span class="hljs-params">user</span>) </span>{
    setAssignedList(<span class="hljs-function">(<span class="hljs-params">prevList</span>) =&gt;</span> {
      <span class="hljs-comment">// Check if the user already exists in the list</span>
      <span class="hljs-keyword">if</span> (prevList.includes(user)) {
        <span class="hljs-comment">// If user exists, remove it from the list</span>
        <span class="hljs-keyword">const</span> updatedList = prevList.filter(<span class="hljs-function">(<span class="hljs-params">item</span>) =&gt;</span> item !== user);
        <span class="hljs-keyword">return</span> updatedList;
      } <span class="hljs-keyword">else</span> {
        <span class="hljs-comment">// If user doesn't exist, add it to the list</span>
        <span class="hljs-keyword">return</span> [...prevList, user];
      }
    });
  }
</code></pre>
<p>To confirm this function works, use the <code>assignedList</code> array to add a check icon to every assigned user.</p>
<pre><code class="lang-jsx">&lt;ul className=<span class="hljs-string">"flex flex-col p-2"</span>&gt;
  {usersArray.map(<span class="hljs-function">(<span class="hljs-params">user</span>) =&gt;</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">li</span>
      <span class="hljs-attr">key</span>=<span class="hljs-string">{user.id}</span>
      <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">flex</span> <span class="hljs-attr">items-center</span> <span class="hljs-attr">gap-2</span> <span class="hljs-attr">p-4</span> <span class="hljs-attr">hover:bg-</span>[#<span class="hljs-attr">2b2c37</span>] <span class="hljs-attr">rounded</span> <span class="hljs-attr">transition-all</span> <span class="hljs-attr">duration-200</span> `}
      <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> handleAssign(user)}
    &gt;
      {assignedList.includes(user) &amp;&amp; <span class="hljs-tag">&lt;<span class="hljs-name">FiCheck</span> /&gt;</span>}

      <span class="hljs-tag">&lt;<span class="hljs-name">img</span>
        <span class="hljs-attr">className</span>=<span class="hljs-string">"w-6 h-6 "</span>
        <span class="hljs-attr">src</span>=<span class="hljs-string">{user.imgUrl}</span>
        <span class="hljs-attr">alt</span>=<span class="hljs-string">{</span>`${<span class="hljs-attr">user.name</span>} <span class="hljs-attr">image</span>`}
      /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>{user.name}<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span></span>
  ))}
&lt;/ul&gt;
</code></pre>
<p>With this change, the dropdown should assign and unassign users on the click of each user.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/05-Assigning-and-unassigning-users-to-the-task.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Assigning and unassigning users to the task</em></p>
<p>To improve the UI, let’s create a component which shows all the assigned users.</p>
<p>Create an <code>AssignedList</code> component and pass in its respective states.</p>
<pre><code class="lang-jsx"> &lt;AssignedList
   assignedList={assignedList}
   setAssignedList={setAssignedList}
  /&gt;
</code></pre>
<p>Then use the assigned array to create some JSX.</p>
<pre><code class="lang-jsx"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">AssignedList</span>(<span class="hljs-params">{ assignedList, setAssignedList }</span>) </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">"mt-4 p-2 shadow-sm bg-[#828fa318] rounded"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"px-2 my-3 font-bold"</span>&gt;</span>Assigned list:<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex flex-wrap gap-4 "</span>&gt;</span>
        {assignedList?.map((user, index) =&gt; (
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span>
            <span class="hljs-attr">key</span>=<span class="hljs-string">{user.id}</span>
            <span class="hljs-attr">className</span>=<span class="hljs-string">"flex items-center gap-1 w-[47.5%] p-2 hover:bg-[#20212c] rounded transition-all duration-200"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>{index + 1}.<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">img</span>
              <span class="hljs-attr">className</span>=<span class="hljs-string">"w-6 h-6 "</span>
              <span class="hljs-attr">src</span>=<span class="hljs-string">{user.imgUrl}</span>
              <span class="hljs-attr">alt</span>=<span class="hljs-string">{</span>`${<span class="hljs-attr">user.name</span>} <span class="hljs-attr">image</span>`}
            /&gt;</span>

            <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>{user.name}<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">"ml-auto cursor-pointer p-1 hover:bg-[#2b2c37] rounded-full"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">FaXmark</span> /&gt;</span>
            <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">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<p>Testing out your component now yields:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/06-Displaying-assigned-users-using-the-AssignedList-component.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Displaying assigned users using the AssignedList component</em></p>
<p>One of the final touches would be to use the <strong>x</strong> icon to remove a user from the assignment.</p>
<p>This can be done using the <code>setAssigned</code> function to filter out the user based on their <code>id</code>.</p>
<pre><code class="lang-jsx"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handleRemove</span>(<span class="hljs-params">id</span>) </span>{
    setAssignedList(<span class="hljs-function">(<span class="hljs-params">assignedList</span>) =&gt;</span>
      assignedList.filter(<span class="hljs-function">(<span class="hljs-params">user</span>) =&gt;</span> user.id !== id)
    );
  }
</code></pre>
<p>Then pass in the user id from the loop.</p>
<pre><code class="lang-jsx"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">AssignedList</span>(<span class="hljs-params">{ assignedList, setAssignedList }</span>) </span>{
  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handleRemove</span>(<span class="hljs-params">id</span>) </span>{
    setAssignedList(<span class="hljs-function">(<span class="hljs-params">assignedList</span>) =&gt;</span>
      assignedList.filter(<span class="hljs-function">(<span class="hljs-params">user</span>) =&gt;</span> user.id !== id)
    );
  }
  <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">"mt-4 p-2 shadow-sm bg-[#828fa318] rounded"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"px-2 my-3 font-bold"</span>&gt;</span>Assigned list:<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex flex-wrap gap-4 "</span>&gt;</span>
        {assignedList?.map((user, index) =&gt; (
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span>
            <span class="hljs-attr">key</span>=<span class="hljs-string">{user.id}</span>
            <span class="hljs-attr">className</span>=<span class="hljs-string">"flex items-center gap-1 w-[47.5%] p-2 hover:bg-[#20212c] rounded transition-all duration-200"</span>
            <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> handleRemove(user.id)}&gt;
            <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>{index + 1}.<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">img</span>
              <span class="hljs-attr">className</span>=<span class="hljs-string">"w-6 h-6 "</span>
              <span class="hljs-attr">src</span>=<span class="hljs-string">{user.imgUrl}</span>
              <span class="hljs-attr">alt</span>=<span class="hljs-string">{</span>`${<span class="hljs-attr">user.name</span>} <span class="hljs-attr">image</span>`}
            /&gt;</span>

            <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>{user.name}<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">"ml-auto cursor-pointer p-1 hover:bg-[#2b2c37] rounded-full"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">FaXmark</span> /&gt;</span>
            <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">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<p>This gives:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/07-Removing-users-from-assignment-using-the-AssignedList-component-1.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Removing users from assignment using the AssignedList component</em></p>
<p>Another final touch would be to close the dropdown list at some user interaction.</p>
<p>To begin, I like using a reusable hook for this, which takes in a reference element and a function to fire when any area outside my target element is clicked.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> { useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-keyword">const</span> useClickOutside = <span class="hljs-function">(<span class="hljs-params">ref, handler</span>) =&gt;</span> {
  <span class="hljs-comment">// console.log(handler, ref);</span>
  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> listener = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
      <span class="hljs-comment">// Do nothing if clicking ref's element or descendent elements</span>
      <span class="hljs-keyword">if</span> (!ref.current || ref.current.contains(event.target)) {
        <span class="hljs-keyword">return</span>;
      }

      handler(event);
    };

    <span class="hljs-built_in">document</span>.addEventListener(<span class="hljs-string">"mousedown"</span>, listener);
    <span class="hljs-built_in">document</span>.addEventListener(<span class="hljs-string">"touchstart"</span>, listener);

    <span class="hljs-keyword">return</span> <span class="hljs-function">() =&gt;</span> {
      <span class="hljs-built_in">document</span>.removeEventListener(<span class="hljs-string">"mousedown"</span>, listener);
      <span class="hljs-built_in">document</span>.removeEventListener(<span class="hljs-string">"touchstart"</span>, listener);
    };
  }, [ref, handler]);
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> useClickOutside;
</code></pre>
<p>Then in our <code>App</code> component, create a ref using the <code>useRef</code> hook to select an element.</p>
<pre><code class="lang-jsx">  <span class="hljs-keyword">const</span> dropdownContainerRef = useRef(<span class="hljs-literal">null</span>);
</code></pre>
<p>Then assign it to your preferred element.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</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> [isDropdownOpen, setIsDropdownOpen] = useState(<span class="hljs-literal">false</span>);

  <span class="hljs-keyword">const</span> [assignedList, setAssignedList] = useState([]);

  <span class="hljs-keyword">const</span> dropdownContainerRef = useRef(<span class="hljs-literal">null</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">"bg-[#2b2c37] h-[100dvh] text-white flex  p-20 gap-4 items-center flex-col"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">" w-[400px] "</span> <span class="hljs-attr">ref</span>=<span class="hljs-string">{dropdownContainerRef}</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-2xl "</span>&gt;</span>Regular Functional React Pattern<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Dropdown</span>
          <span class="hljs-attr">usersArray</span>=<span class="hljs-string">{usersArray}</span>
          <span class="hljs-attr">isDropdownOpen</span>=<span class="hljs-string">{isDropdownOpen}</span>
          <span class="hljs-attr">setIsDropdownOpen</span>=<span class="hljs-string">{setIsDropdownOpen}</span>
          <span class="hljs-attr">assignedList</span>=<span class="hljs-string">{assignedList}</span>
          <span class="hljs-attr">setAssignedList</span>=<span class="hljs-string">{setAssignedList}</span>
        /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">AssignedList</span>
          <span class="hljs-attr">assignedList</span>=<span class="hljs-string">{assignedList}</span>
          <span class="hljs-attr">setAssignedList</span>=<span class="hljs-string">{setAssignedList}</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>
  );
}
</code></pre>
<p>Finally, import your hook and pass in the reference element and the function handler function for closing the dropdown.</p>
<pre><code class="lang-jsx"> useClickOutside(dropdownContainerRef, <span class="hljs-function">() =&gt;</span> {
    setIsDropdownOpen(<span class="hljs-literal">false</span>);
  });
</code></pre>
<p>Testing your component now gives:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/08-Closing-the-dropdown-component-with-outside-clicks.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Closing the dropdown component with outside clicks</em></p>
<p>Or using a predefined button in the dropdown.</p>
<pre><code class="lang-jsx">&lt;button
  className=<span class="hljs-string">"px-4 w-full py-2 flex items-center justify-between rounded border border-[#828FA340] hover:border-primary cursor-pointer relative"</span>
  onClick={toggleDropdown}
&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"block"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">FiChevronDown</span> <span class="hljs-attr">color</span>=<span class="hljs-string">"#635FC7"</span> <span class="hljs-attr">size</span>=<span class="hljs-string">{24}</span> /&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span></span>
  {isDropdownOpen &amp;&amp; (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"absolute bottom-full translate-x-9 left-full translate-y-full rounded bg-[#20212c] w-max"</span>&gt;</span>
      {/* Close button */}
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span>
        <span class="hljs-attr">className</span>=<span class="hljs-string">"absolute top-0 right-0 flex items-center justify-center -translate-y-full gap-2 bg-[#C0392B] px-2 py-1 rounded-t"</span>
        <span class="hljs-attr">onClick</span>=<span class="hljs-string">{(e)</span> =&gt;</span> {
          e.stopPropagation();
          setIsDropdownOpen(false);
          console.log(isDropdownOpen);
        }}
      &gt;
        <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>Close<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">FaXmark</span> <span class="hljs-attr">size</span>=<span class="hljs-string">{20}</span> /&gt;</span>
        <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">ul</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex flex-col p-2"</span>&gt;</span>
        {usersArray.map((user) =&gt; (
          <span class="hljs-tag">&lt;<span class="hljs-name">li</span>
            <span class="hljs-attr">key</span>=<span class="hljs-string">{user.id}</span>
            <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">flex</span> <span class="hljs-attr">items-center</span> <span class="hljs-attr">gap-2</span> <span class="hljs-attr">p-4</span> <span class="hljs-attr">hover:bg-</span>[#<span class="hljs-attr">2b2c37</span>] <span class="hljs-attr">rounded</span> <span class="hljs-attr">transition-all</span> <span class="hljs-attr">duration-200</span>`}
            <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> handleAssign(user)}
          &gt;
            {assignedList.includes(user) &amp;&amp; <span class="hljs-tag">&lt;<span class="hljs-name">FiCheck</span> /&gt;</span>}
            <span class="hljs-tag">&lt;<span class="hljs-name">img</span>
              <span class="hljs-attr">className</span>=<span class="hljs-string">"w-6 h-6"</span>
              <span class="hljs-attr">src</span>=<span class="hljs-string">{user.imgUrl}</span>
              <span class="hljs-attr">alt</span>=<span class="hljs-string">{</span>`${<span class="hljs-attr">user.name</span>} <span class="hljs-attr">image</span>`}
            /&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>{user.name}<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
          <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>
  )}
&lt;/button&gt;
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/09-Closing-the-dropdown-with-the-designated-button.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Closing the dropdown with the designated button</em></p>
<p>The final change is an opinionated one as I’d rather show something else if there aren’t any users currently assigned to the task.</p>
<pre><code class="lang-jsx">{assignedList.length === <span class="hljs-number">0</span> ? (
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mt-4 p-2 shadow-sm bg-[#828fa318] rounded"</span>&gt;</span>
    No users assigned to the task yet.
  <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span></span>
) : (
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">AssignedList</span>
    <span class="hljs-attr">assignedList</span>=<span class="hljs-string">{assignedList}</span>
    <span class="hljs-attr">setAssignedList</span>=<span class="hljs-string">{setAssignedList}</span>
  /&gt;</span></span>
)}
</code></pre>
<p>This brings the UI to:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/10-Showing-a-default-text-when-no-users-are-assigned.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Showing a default text when no users are assigned</em></p>
<h3 id="heading-the-compound-component-pattern-method">The Compound Component Pattern Method</h3>
<p>Now, for the main event. Start by creating a context which wraps the entire component.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> UserAssignContext = createContext();
</code></pre>
<p>Then we gather all the necessary data and functions that our dropdown and its components will need. This includes things like the list of assigned users, a function to update that list, and whether the dropdown is currently open or not.</p>
<p>After which, you provide those values to all its children component.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> UserAssignDropdown = <span class="hljs-function">(<span class="hljs-params">{
  children,
  assignedList,
  setAssignedList,
  users,
}</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> UserAssignDropdownRef = useRef(<span class="hljs-literal">null</span>);
  <span class="hljs-keyword">const</span> [isDropdownOpen, setIsDropdownOpen] = useState(<span class="hljs-literal">false</span>);

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">UserAssignContext.Provider</span>
      <span class="hljs-attr">value</span>=<span class="hljs-string">{{</span>
        <span class="hljs-attr">assignedList</span>,
        <span class="hljs-attr">users</span>,
        <span class="hljs-attr">UserAssignDropdownRef</span>,
        <span class="hljs-attr">isDropdownOpen</span>,
        <span class="hljs-attr">setIsDropdownOpen</span>,
        <span class="hljs-attr">setAssignedList</span>,
      }}&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">ref</span>=<span class="hljs-string">{UserAssignDropdownRef}</span>&gt;</span>{children}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">UserAssignContext.Provider</span>&gt;</span></span>
  );
};
</code></pre>
<p>With our context set up, it's time to craft the individual components that will make up our dropdown. Each component will interact with the context to access and manipulate the necessary data and functions.</p>
<p>Start by copying each style from the components we just built.</p>
<h4 id="heading-the-header-component">The Header Component</h4>
<p>This component remains the same.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> Header = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mt-4 mb-2 text-sm"</span>&gt;</span>Assign task to:<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span></span>;
};
</code></pre>
<h4 id="heading-the-close-component">The Close Component</h4>
<p>This component obtains the function for toggling the dropdown from the context.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> Close = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> { setIsDropdownOpen } = useContext(UserAssignContext);
  <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">"absolute top-0 right-0 flex items-center justify-center -translate-y-full gap-2 bg-[#C0392B] px-2 py-1 rounded-t"</span>
      <span class="hljs-attr">onClick</span>=<span class="hljs-string">{(e)</span> =&gt;</span> {
        e.stopPropagation();
        setIsDropdownOpen(false);
      }}&gt;
      <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>Close<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">FaXmark</span> <span class="hljs-attr">size</span>=<span class="hljs-string">{20}</span> /&gt;</span>
      <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>
  );
};
</code></pre>
<h4 id="heading-the-assigned-list-component">The Assigned List Component</h4>
<p>This component displays the list of assigned users, as well as removing users from the list.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> AssignedList = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> { assignedList, setAssignedList } = useContext(UserAssignContext);

  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handleRemove</span>(<span class="hljs-params">id</span>) </span>{
    setAssignedList(<span class="hljs-function">(<span class="hljs-params">assignedList</span>) =&gt;</span>
      assignedList.filter(<span class="hljs-function">(<span class="hljs-params">user</span>) =&gt;</span> user.id !== id)
    );
  }

  <span class="hljs-keyword">if</span> (assignedList.length === <span class="hljs-number">0</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">className</span>=<span class="hljs-string">"mt-4 p-2 shadow-sm bg-[#828fa318] rounded"</span>&gt;</span>
        No users assigned to the task yet.
      <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span></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">"mt-4 p-2 shadow-sm bg-[#828fa318] rounded"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"px-2 my-3 font-bold"</span>&gt;</span>Assigned list:<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex flex-wrap gap-4 "</span>&gt;</span>
        {assignedList?.map((user, index) =&gt; (
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span>
            <span class="hljs-attr">key</span>=<span class="hljs-string">{user.id}</span>
            <span class="hljs-attr">className</span>=<span class="hljs-string">"flex items-center gap-1 w-[47.5%] p-2 hover:bg-[#20212c] rounded transition-all duration-200"</span>
            <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> handleRemove(user.id)}&gt;
            <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>{index + 1}.<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">img</span>
              <span class="hljs-attr">className</span>=<span class="hljs-string">"w-6 h-6 "</span>
              <span class="hljs-attr">src</span>=<span class="hljs-string">{user.imgUrl}</span>
              <span class="hljs-attr">alt</span>=<span class="hljs-string">{</span>`${<span class="hljs-attr">user.name</span>} <span class="hljs-attr">image</span>`}
            /&gt;</span>

            <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>{user.name}<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">"ml-auto cursor-pointer p-1 hover:bg-[#2b2c37] rounded-full"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">FaXmark</span> /&gt;</span>
            <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">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
};
</code></pre>
<h4 id="heading-the-item-component">The Item Component</h4>
<p>This component represents each user and the functionality of adding and removing users from the assigned list.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> Item = <span class="hljs-function">(<span class="hljs-params">{ user }</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> { assignedList, setAssignedList } = useContext(UserAssignContext);

  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handleAssign</span>(<span class="hljs-params">user</span>) </span>{
    setAssignedList(<span class="hljs-function">(<span class="hljs-params">prevList</span>) =&gt;</span> {
      <span class="hljs-comment">// Check if the user already exists in the list</span>
      <span class="hljs-keyword">if</span> (prevList.includes(user)) {
        <span class="hljs-comment">// If user exists, remove it from the list</span>
        <span class="hljs-keyword">const</span> updatedList = prevList.filter(<span class="hljs-function">(<span class="hljs-params">item</span>) =&gt;</span> item !== user);
        <span class="hljs-keyword">return</span> updatedList;
      } <span class="hljs-keyword">else</span> {
        <span class="hljs-comment">// If user doesn't exist, add it to the list</span>
        <span class="hljs-keyword">return</span> [...prevList, user];
      }
    });
  }

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">li</span>
      <span class="hljs-attr">key</span>=<span class="hljs-string">{user.id}</span>
      <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">flex</span> <span class="hljs-attr">items-center</span> <span class="hljs-attr">gap-2</span> <span class="hljs-attr">p-4</span> <span class="hljs-attr">hover:bg-</span>[#<span class="hljs-attr">2b2c37</span>] <span class="hljs-attr">rounded</span> <span class="hljs-attr">transition-all</span> <span class="hljs-attr">duration-200</span> `}
      <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> handleAssign(user)}&gt;
      {assignedList.includes(user) &amp;&amp; <span class="hljs-tag">&lt;<span class="hljs-name">FiCheck</span> /&gt;</span>}

      <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"w-6 h-6 "</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{user.imgUrl}</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">{</span>`${<span class="hljs-attr">user.name</span>} <span class="hljs-attr">image</span>`} /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>{user.name}<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span></span>
  );
};
</code></pre>
<h4 id="heading-the-button-component">The Button Component</h4>
<p>This component controls displaying the <code>List</code> component (floating dropdown).</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> Button = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> { setIsDropdownOpen } = useContext(UserAssignContext);
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">button</span>
      <span class="hljs-attr">className</span>=<span class="hljs-string">"  px-4 py-2 flex items-center justify-between w-full rounded border border-[#828FA340] hover:border-primary cursor-pointer relative "</span>
      <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> setIsDropdownOpen(true)}&gt;
      <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"block"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">FiChevronDown</span> <span class="hljs-attr">color</span>=<span class="hljs-string">"#635FC7"</span> <span class="hljs-attr">size</span>=<span class="hljs-string">{24}</span> /&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>

      <span class="hljs-tag">&lt;<span class="hljs-name">UserAssignDropdown.List</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></span>
  );
};
</code></pre>
<p>To combine this component into a singular compound component (compound component), you assign each component to the parent, like so;</p>
<pre><code class="lang-jsx">UserAssignDropdown.List = ListContainer;
UserAssignDropdown.Item = Item;
UserAssignDropdown.Header = Header;
UserAssignDropdown.Button = Button;
UserAssignDropdown.AssignedList = AssignedList;
UserAssignDropdown.Close = Close;
</code></pre>
<p>Next, import your compound component in your <code>App</code> component as a wrapper component and pass in the appropriate states.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</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> [assignedList, setAssignedList] = useState([]);

  <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">"bg-[#2b2c37] h-[100dvh] text-white flex  p-20 gap-4 items-center flex-col"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">" w-[400px] "</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-2xl "</span>&gt;</span>Compound Component Pattern<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">UserAssignDropdown</span>
          <span class="hljs-attr">assignedList</span>=<span class="hljs-string">{assignedList}</span>
          <span class="hljs-attr">setAssignedList</span>=<span class="hljs-string">{setAssignedList}</span>
          <span class="hljs-attr">users</span>=<span class="hljs-string">{usersArray}</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">UserAssignDropdown</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>
  );
}
</code></pre>
<p>Then in the wrapper, render the appropriate children.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</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> [assignedList, setAssignedList] = useState([]);

  <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">"bg-[#2b2c37] h-[100dvh] text-white flex  p-20 gap-4 items-center flex-col"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">" w-[400px] "</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-2xl "</span>&gt;</span>Compound Component Pattern<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">UserAssignDropdown</span>
          <span class="hljs-attr">assignedList</span>=<span class="hljs-string">{assignedList}</span>
          <span class="hljs-attr">setAssignedList</span>=<span class="hljs-string">{setAssignedList}</span>
          <span class="hljs-attr">users</span>=<span class="hljs-string">{usersArray}</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">UserAssignDropdown.Header</span> /&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">UserAssignDropdown.Button</span> /&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">UserAssignDropdown.AssignedList</span> /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">UserAssignDropdown</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>
  );
}
</code></pre>
<p>Finally, use the custom hook we created earlier to close the dropdown when you click outside the component.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> UserAssignContext = createContext();
<span class="hljs-keyword">const</span> UserAssignDropdown = <span class="hljs-function">(<span class="hljs-params">{
  children,
  assignedList,
  setAssignedList,
  users,
}</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> UserAssignDropdownRef = useRef(<span class="hljs-literal">null</span>);
  <span class="hljs-keyword">const</span> [isDropdownOpen, setIsDropdownOpen] = useState(<span class="hljs-literal">false</span>);

  useClickOutside(UserAssignDropdownRef, <span class="hljs-function">() =&gt;</span> {
    setIsDropdownOpen(<span class="hljs-literal">false</span>);
  });

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">UserAssignContext.Provider</span>
      <span class="hljs-attr">value</span>=<span class="hljs-string">{{</span>
        <span class="hljs-attr">assignedList</span>,
        <span class="hljs-attr">users</span>,
        <span class="hljs-attr">UserAssignDropdownRef</span>,
        <span class="hljs-attr">isDropdownOpen</span>,
        <span class="hljs-attr">setIsDropdownOpen</span>,
        <span class="hljs-attr">setAssignedList</span>,
      }}&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">ref</span>=<span class="hljs-string">{UserAssignDropdownRef}</span>&gt;</span>{children}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">UserAssignContext.Provider</span>&gt;</span></span>
  );
};
</code></pre>
<p>And with that, your component works the same!</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/11-replicating-the-same-funtionality-with-the-compound-component-pattern.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Replicating the same functionality with the compound component pattern</em></p>
<p>But why stop here?</p>
<p>With this pattern, changing the look of the component is as easy as changing the order in which you render them in their parent. For instance, if you wanted the button first, you simply change the order in the parent wrapper.</p>
<pre><code class="lang-jsx">&lt;UserAssignDropdown
  assignedList={assignedList}
  setAssignedList={setAssignedList}
  users={usersArray}
&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">UserAssignDropdown.Button</span> /&gt;</span></span>
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">UserAssignDropdown.Header</span> /&gt;</span></span>
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">UserAssignDropdown.AssignedList</span> /&gt;</span></span>
&lt;/UserAssignDropdown&gt;
</code></pre>
<p>And the UI responds accordingly.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/04-order-of-rendering-in-compound-component-changed.png" alt="Image" width="600" height="400" loading="lazy">
<em>Order of rendering in compound component changed</em></p>
<p>This component is also flexible enough to change the layout of elements via props.</p>
<p>Just by passing style props via a parent:</p>
<pre><code class="lang-jsx">&lt;UserAssignDropdown
  assignedList={assignedList}
  setAssignedList={setAssignedList}
  users={usersArray}
&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">UserAssignDropdown.Header</span> /&gt;</span></span>
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">UserAssignDropdown.Button</span>
    <span class="hljs-attr">listStyles</span>=<span class="hljs-string">{</span>"!<span class="hljs-attr">-left-5</span> !<span class="hljs-attr">-translate-x-full</span> <span class="hljs-attr">bg-</span>[#<span class="hljs-attr">605e80</span>] <span class="hljs-attr">text-white</span> <span class="hljs-attr">border</span>"}
  /&gt;</span></span>
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">UserAssignDropdown.AssignedList</span> /&gt;</span></span>
&lt;/UserAssignDropdown&gt;
</code></pre>
<p>And receiving those props in the child:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> Button = <span class="hljs-function">(<span class="hljs-params">{ listStyles }</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> { setIsDropdownOpen, UserAssignDropdownRef } =
    useContext(UserAssignContext);
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">button</span>
      <span class="hljs-attr">className</span>=<span class="hljs-string">"  px-4 py-2 flex items-center justify-between w-full rounded border border-[#828FA340] hover:border-primary cursor-pointer relative "</span>
      <span class="hljs-attr">ref</span>=<span class="hljs-string">{UserAssignDropdownRef}</span>
      <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> setIsDropdownOpen(true)}&gt;
      <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"block"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">FiChevronDown</span> <span class="hljs-attr">color</span>=<span class="hljs-string">"#635FC7"</span> <span class="hljs-attr">size</span>=<span class="hljs-string">{24}</span> /&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">UserAssignDropdown.List</span> <span class="hljs-attr">listStyles</span>=<span class="hljs-string">{listStyles}</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">const</span> ListContainer = <span class="hljs-function">(<span class="hljs-params">{ listStyles }</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> { users, isDropdownOpen } = useContext(UserAssignContext);

  <span class="hljs-keyword">return</span> (
    isDropdownOpen &amp;&amp; (
      <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ul</span>
        <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">absolute</span> <span class="hljs-attr">bottom-full</span> <span class="hljs-attr">translate-x-9</span>  <span class="hljs-attr">left-full</span> <span class="hljs-attr">translate-y-full</span> <span class="hljs-attr">rounded</span> <span class="hljs-attr">bg-</span>[#<span class="hljs-attr">20212c</span>] <span class="hljs-attr">w-max</span> ${<span class="hljs-attr">listStyles</span>}`}&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">UserAssignDropdown.Close</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex flex-col p-2"</span>&gt;</span>
          {users?.map((user, index) =&gt; (
            <span class="hljs-tag">&lt;<span class="hljs-name">UserAssignDropdown.Item</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{index}</span> <span class="hljs-attr">user</span>=<span class="hljs-string">{user}</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">ul</span>&gt;</span></span>
    )
  );
};
</code></pre>
<p>You can easily change the look of the component.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/12-Using-props-to-customize-the-compound-component.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Using props to customize the compound component</em></p>
<h2 id="heading-comparison-between-the-regular-and-the-compound-component-method">Comparison between the Regular and the Compound Component method</h2>
<p>Alright, let's take a step back and compare the two approaches we've just explored.</p>
<h3 id="heading-simplicity-and-organization">Simplicity and Organization</h3>
<ul>
<li><strong>Regular Method</strong>: Picture it like baking a cake all in one big bowl. With the regular method, we can create a single component responsible for everything in the dropdown – the button, the list, and all the ingredients. It's like having a big recipe card with all the steps jumbled together. It gets the job done, but it can be a bit messy and hard to follow, especially when you're trying to tweak just one part of the recipe.</li>
<li><strong>Compound Component Method</strong>: Now imagine we've got different bowls for each ingredient, a separate one for flour, another for sugar, and so on. That's the compound component pattern. Each part of the dropdown has its own space to shine. It's like organizing your kitchen – everything has its place. This makes it easier to understand and modify. Need to change the flour? You know just where to look.</li>
</ul>
<h3 id="heading-flexibility-and-customization">Flexibility and Customization</h3>
<ul>
<li><strong>Regular Method</strong>: With our single-bowl approach, making changes to specific parts of the dropdown can be a bit like trying to swap out ingredients in that big cake mix. Sure, you can do it, but it's not always easy. Want a different flavor of cake? You might need to dig through the whole bowl to find where to add it.</li>
<li><strong>Compound Component Method</strong>: With the compound component pattern, it's like having separate containers for each flavor. Need to add chocolate chips? Just grab the chocolate container and sprinkle away. Each component has its job, making it simpler to customize. Want to change the color of the button? No problem, it's right there in its container.</li>
</ul>
<h3 id="heading-reuse-and-maintenance">Reuse and Maintenance</h3>
<ul>
<li><strong>Regular Method</strong>: When your recipe is all mixed up in one bowl, it can be hard to reuse parts of it for another dish. Plus, as your kitchen gets busier, it's easy for things to get messy and hard to keep track of. You might find yourself rewriting the recipe every time you want to make something new.</li>
<li><strong>Compound Component Method</strong>: With the compound component pattern, it's like having a set of reusable tools in your kitchen. Need to make a different kind of cake? Just grab the tools you need and get baking. Each component is like a specialized gadget – easy to reuse and maintain. And when your kitchen is organized, it's a breeze to whip up something new.</li>
</ul>
<h3 id="heading-additional-information">Additional Information</h3>
<p>Here are links to all the resources you may need from this article.</p>
<ul>
<li><a target="_blank" href="https://github.com/Daiveedjay/React-Dropdown-Component/tree/Starter">Starter files</a></li>
<li><a target="_blank" href="https://github.com/Daiveedjay/React-Dropdown-Component/tree/Regular-react-pattern">Regular Function Pattern</a></li>
<li><a target="_blank" href="https://github.com/Daiveedjay/React-Dropdown-Component/tree/Compound-component-pattern">Compound Component Pattern</a></li>
</ul>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In the end, both methods have their place in the kitchen – er, I mean, in your code. The regular method is like your trusty old mixing bowl – reliable and familiar, but maybe not the most efficient for every recipe. </p>
<p>The compound component Pattern is like a well-organized kitchen, with everything in its place and ready to go. It might take a bit more setup, but it can make your life a whole lot easier in the long run. So, depending on what you're cooking up, choose the method that suits your taste– and happy coding! 🍰🎨  </p>
<h3 id="heading-contact-information">Contact Information</h3>
<p>Want to connect or contact me? Feel free to hit me up on the following:</p>
<ul>
<li>Twitter / X: <a target="_blank" href="https://twitter.com/JajaDavid8">@jajadavid8</a></li>
<li>LinkedIn: <a target="_blank" href="https://www.linkedin.com/in/david-jaja-8084251b4/">David Jaja</a></li>
<li>Email: Jajadavidjid@gmail.com</li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build a Marquee Component with React ]]>
                </title>
                <description>
                    <![CDATA[ When you think of marquees, you often envision the vibrant lights and spinning displays at amusement parks, bringing back fond memories of your childhood. Similarly in web applications, marquees inject a lively visual sense by effortlessly grabbing a... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-build-a-marquee-component-with-react/</link>
                <guid isPermaLink="false">66bb89057a6500a14ba5b767</guid>
                
                    <category>
                        <![CDATA[ components ]]>
                    </category>
                
                    <category>
                        <![CDATA[ projects ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ David Jaja ]]>
                </dc:creator>
                <pubDate>Tue, 09 Apr 2024 12:41:24 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/04/Group-297.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>When you think of marquees, you often envision the vibrant lights and spinning displays at amusement parks, bringing back fond memories of your childhood.</p>
<p>Similarly in web applications, marquees inject a lively visual sense by effortlessly grabbing attention and infusing your online projects with dynamism.</p>
<p>Join me as we explore how to build an engaging marquee component in React.<br>This step-by-step guide targets everyone regardless of skill level, we aim to make your experience with React both enjoyable and useful.</p>
<h2 id="heading-what-well-cover"><strong>What We'll Cover:</strong></h2>
<ol>
<li><a class="post-section-overview" href="#heading-understanding-marquee-components">Understanding Marquee Components</a></li>
<li><a class="post-section-overview" href="#heading-benefits-of-marquees">Benefits of Marquees</a></li>
<li><a class="post-section-overview" href="#heading-planning-and-designing-the-marquee-component">Planning and Designing the Marquee Component</a></li>
<li><a class="post-section-overview" href="#heading-how-to-implement-the-marquee-component">How to Implement the Marquee Component</a></li>
<li><a class="post-section-overview" href="#how-to-enhance-enhance-the-marquee-component">How to Enhance the Marquee Component</a></li>
<li><a target="_blank" href="https://www.freecodecamp.org/news/p/0148db11-7178-4632-b727-2321d7e96b01/best-practices-and-tips-for-marquee-component-development">Best Practices and Tips for Marquee Component Development</a></li>
<li><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></li>
</ol>
<h2 id="heading-prerequisites">Prerequisites</h2>
<ul>
<li>Fundamentals of HTML and CSS</li>
<li>Fundamentals of ES6 JavaScript and React</li>
</ul>
<h2 id="heading-understanding-marquee-components">Understanding Marquee Components</h2>
<p>A marquee represents a continuous section of text or visual content (such as pictures) that scrolls automatically in a horizontal direction.</p>
<p>Although the official <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/marquee">HTML Marquee element</a> is obsolete and its use is heavily discouraged, the concept of scrolling, endless elements to add zest to a webpage is still very much in use, and can be found on numerous modern websites.</p>
<p>This effect is realized through <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_animations/Using_CSS_animations">CSS animations</a>, offering a more efficient, fluid, and lightweight animation outcome.</p>
<p>A visual example of a marquee component from <a target="_blank" href="https://webflow.com/made-in-webflow/website/ujjo-Rebuild">Webflow</a> is shown below.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/03/00-Example-marquee.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Webflow Example</em></p>
<h2 id="heading-benefits-of-marquees">Benefits of Marquees</h2>
<p>They have a bunch of usefulness such as:</p>
<ul>
<li><strong>Attention-grabbing</strong>: Marquees are excellent for drawing attention to specific content on a webpage. Whether it's a special offer, announcement, or featured content, a moving marquee naturally catches the eye.</li>
<li><strong>Visual Appeal</strong>: Adding a touch of motion to your website enhances its visual appeal. Marquees can bring life to a page, making it more dynamic and engaging for users.</li>
<li><strong>Highlighting Important Information</strong>: When you want to emphasize critical information like breaking news, upcoming events, or urgent messages, a marquee is an effective way to ensure that users don't miss out.</li>
<li><strong>Event Promotion</strong>: They are particularly useful for promoting events or time-sensitive activities. Their scrolling nature allows you to display event details, dates, and highlights space-efficiently.</li>
<li><strong>Ticker-Style Updates</strong>: For displaying real-time updates, such as stock prices, news headlines, or social media feeds, marquees provide a ticker-style format that keeps information continuously flowing for users.</li>
<li><strong>Interactive Banners</strong>: They can serve as interactive banners, allowing users to click on specific items as they scroll by. This can be a creative way to lead users to different sections or pages of your website.</li>
<li><strong>Dynamic Product Showcases</strong>: E-commerce websites can benefit from marquees by showcasing new products or featured items in a visually engaging way, encouraging users to explore the offerings.</li>
<li><strong>Call-to-Action Emphasis</strong>: If you have specific call-to-action messages, using them can give prominence and ensure that they don't go unnoticed.</li>
<li><strong>Breaking Monotony</strong>: In long pages or static content, a well-designed marquee can break the monotony and add an element of surprise, making the user experience more interesting.</li>
<li><strong>Versatility</strong>: They are versatile and can be customized to suit various styles and themes, making them a flexible tool for web designers seeking to create unique and memorable user interfaces.</li>
</ul>
<h2 id="heading-planning-and-designing-the-marquee-component">Planning and Designing the Marquee Component</h2>
<p>Before you start coding, it's important to plan and design your component and consider factors such as:</p>
<ul>
<li><strong>Define Content</strong>: Clearly outline the content you want to display in the component. This could include text, images, or a combination of both.</li>
<li><strong>Scroll Speed</strong>: Determine the desired scrolling speed to be used. Consider the optimal pace for readability and visual appeal.</li>
<li><strong>Visual Design</strong>: Sketch or visualize how you want it to look. Decide on colors, fonts, and any additional styling to align with your overall design scheme.</li>
<li><strong>Behavior at Scroll End</strong>: Consider its behavior when it reaches the end of its scroll position. Decide whether it should loop continuously, bounce back and forth, or have a specific end-state.</li>
<li><strong>User Interaction</strong>: If applicable, plan for any user interaction. This could include pausing on hover or allowing users to click on items within the marquee.</li>
<li><strong>Responsive Design</strong>: Ensure that your component is designed to be responsive, adapting seamlessly to different screen sizes and devices.</li>
<li><strong>Testing Considerations</strong>: Anticipate potential challenges or adjustments needed during the testing phase. Plan for how it will behave on various browsers and devices.</li>
<li><strong>Accessibility</strong>: Keep accessibility in mind, ensuring that users with different disabilities can still access and understand the content within it.</li>
</ul>
<h2 id="heading-how-to-implement-the-marquee-component">How to Implement the Marquee Component</h2>
<p>To implement the component, start by creating a React environment with <a target="_blank" href="https://vitejs.dev/guide/">Vite</a>.</p>
<pre><code class="lang-bash">npm create vite@latest
</code></pre>
<p>After which you navigate to your project directory, install the necessary packages and start up the dev server.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/03/01-react-server-after-installation-.png" alt="Image" width="600" height="400" loading="lazy">
<em>Setting up dev server</em></p>
<p>Next, create the elements for the JSX mockup for your component.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</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">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">" main__container"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>My Marquee<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">section</span> <span class="hljs-attr">className</span>=<span class="hljs-string">" "</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Default Behaviour<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"marquee"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"marquee__content"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">" marquee__item"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{AndroidLogo}</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</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> <span class="hljs-attr">className</span>=<span class="hljs-string">" marquee__item"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{BehanceLogo}</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</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> <span class="hljs-attr">className</span>=<span class="hljs-string">" marquee__item"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{GoogleLogo}</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</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> <span class="hljs-attr">className</span>=<span class="hljs-string">" marquee__item"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{InstagramLogo}</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</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> <span class="hljs-attr">className</span>=<span class="hljs-string">" marquee__item"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{PaypalLogo}</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</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> <span class="hljs-attr">className</span>=<span class="hljs-string">" marquee__item"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{SpotifyLogo}</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</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">ul</span>&gt;</span>

          <span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">aria-hidden</span>=<span class="hljs-string">"true"</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"marquee__content"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">" marquee__item"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{AndroidLogo}</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</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> <span class="hljs-attr">className</span>=<span class="hljs-string">" marquee__item"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{BehanceLogo}</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</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> <span class="hljs-attr">className</span>=<span class="hljs-string">" marquee__item"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{GoogleLogo}</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</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> <span class="hljs-attr">className</span>=<span class="hljs-string">" marquee__item"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{InstagramLogo}</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</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> <span class="hljs-attr">className</span>=<span class="hljs-string">" marquee__item"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{PaypalLogo}</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</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> <span class="hljs-attr">className</span>=<span class="hljs-string">" marquee__item"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{SpotifyLogo}</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</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">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">section</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<p>This includes a header for the component, the behavior of the component and the data in the component to be animated.</p>
<p>It is important to duplicate the data in the component as it would be used to achieve the duplicate effect. However, we’re hiding the second list initially using the <code>aria-hidden='true'</code> property.</p>
<p>To make it more visually appealing, add these styles.</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">body</span> {
  <span class="hljs-attribute">font-family</span>: system-ui, -apple-system, BlinkMacSystemFont, <span class="hljs-string">"Segoe UI"</span>, Roboto,
    Oxygen, Ubuntu, Cantarell, <span class="hljs-string">"Open Sans"</span>, <span class="hljs-string">"Helvetica Neue"</span>, sans-serif;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">2rem</span>;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
  <span class="hljs-attribute">min-height</span>: <span class="hljs-number">100vh</span>;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">1rem</span>;
  <span class="hljs-attribute">line-height</span>: <span class="hljs-number">1.5</span>;
}

* { <span class="hljs-attribute">box-sizing</span>: border-box; }

<span class="hljs-selector-tag">h1</span> {
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">2rem</span>;
  <span class="hljs-attribute">font-weight</span>: <span class="hljs-number">600</span>;
  <span class="hljs-attribute">line-height</span>: <span class="hljs-number">1.2</span>;
  <span class="hljs-attribute">margin-block</span>: <span class="hljs-number">2rem</span> <span class="hljs-number">1rem</span>;
  <span class="hljs-attribute">text-align</span>: center;
}

<span class="hljs-selector-tag">h2</span> {
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">1.25rem</span>;
  <span class="hljs-attribute">font-weight</span>: <span class="hljs-number">600</span>;
}

<span class="hljs-selector-tag">section</span> { <span class="hljs-attribute">margin-block</span>: <span class="hljs-number">3rem</span>; }

<span class="hljs-selector-class">.main__container</span> {
  <span class="hljs-attribute">max-width</span>: <span class="hljs-number">1000px</span>;
  <span class="hljs-attribute">margin-inline</span>: auto;
  <span class="hljs-attribute">background</span>: <span class="hljs-built_in">rgb</span>(<span class="hljs-number">124</span>, <span class="hljs-number">145</span>, <span class="hljs-number">175</span>);
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">3rem</span>;
}

<span class="hljs-comment">/* Marquee styles */</span>
<span class="hljs-selector-class">.marquee</span> {
  <span class="hljs-attribute">--gap</span>: <span class="hljs-number">1rem</span>;
  <span class="hljs-attribute">position</span>: relative;
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">overflow</span>: hidden;
  <span class="hljs-attribute">user-select</span>: none;
  <span class="hljs-attribute">gap</span>: <span class="hljs-built_in">var</span>(--gap);
  <span class="hljs-attribute">border</span>: <span class="hljs-number">2px</span> dashed lightgray;
}

<span class="hljs-selector-class">.marquee__content</span> {
  <span class="hljs-attribute">flex-shrink</span>: <span class="hljs-number">0</span>;
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">justify-content</span>: space-around;
  <span class="hljs-attribute">gap</span>: <span class="hljs-built_in">var</span>(--gap);
  <span class="hljs-attribute">min-width</span>: <span class="hljs-number">100%</span>;
}

<span class="hljs-selector-class">.marquee__content</span> <span class="hljs-selector-tag">img</span> {
  <span class="hljs-attribute">max-width</span>: <span class="hljs-number">2rem</span>;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
  <span class="hljs-attribute">object-fit</span>: contain;
}

<span class="hljs-selector-class">.marquee__content</span> &gt; * {
  <span class="hljs-attribute">flex</span>: <span class="hljs-number">0</span> <span class="hljs-number">0</span> auto;
  <span class="hljs-attribute">color</span>: white;
  <span class="hljs-attribute">background</span>: <span class="hljs-number">#e8daef</span>;
  <span class="hljs-attribute">margin</span>: <span class="hljs-number">2px</span>;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">1rem</span> <span class="hljs-number">2rem</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">0.25rem</span>;
  <span class="hljs-attribute">text-align</span>: center;
}

<span class="hljs-selector-class">.marquee__item</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-selector-tag">ul</span> { <span class="hljs-attribute">padding-left</span>: <span class="hljs-number">0</span>; }
</code></pre>
<p>At the moment, your component should look like this;</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/03/02-UI-after-applying-styles.png" alt="Image" width="600" height="400" loading="lazy">
<em>UI after applying styles</em></p>
<p>To animate this component, start by defining custom <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/CSS/@keyframes">CSS keyframes</a>.</p>
<pre><code class="lang-css"><span class="hljs-keyword">@keyframes</span> scroll {
  <span class="hljs-selector-tag">from</span> { <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">translateX</span>(<span class="hljs-number">0</span>); }
  <span class="hljs-selector-tag">to</span> { <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">translateX</span>(calc(-<span class="hljs-number">100%</span> - var(--gap))); }
}
</code></pre>
<p><strong>Note</strong>: The gap used is the same gap between the marquee items.<br>Then, assign those keyframes to a class.</p>
<pre><code class="lang-css"><span class="hljs-comment">/* Enable animation */</span>
<span class="hljs-selector-class">.enable-animation</span> <span class="hljs-selector-class">.marquee__content</span> {
  <span class="hljs-attribute">animation</span>: scroll <span class="hljs-number">10s</span> linear infinite;
}
</code></pre>
<p>Finally, add that class to your section element.</p>
<pre><code class="lang-jsx">&lt;section className=<span class="hljs-string">"enable-animation"</span>&gt;
</code></pre>
<p>And with that, your component should already be animating.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/03/03-Animated-marquee.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Animated marquee</em></p>
<h2 id="heading-how-to-enhance-the-marquee-component">How to Enhance the Marquee Component</h2>
<p>This component goes beyond the regular infinite animations (as shown above), it often possess some extra functionalities such as:</p>
<ul>
<li><strong>Pause on Hover</strong>: While using a marquee can be beneficial to show a bunch of content more dynamically, the speed of the animation or the position of the information relevant to the user might cause issues, especially for slow readers.</li>
</ul>
<p>To fix this, you can implement a pause functionality to halt it when the user hovers over it. Just add the CSS code below.</p>
<pre><code class="lang-css"><span class="hljs-comment">/* Pause on hover */</span>
<span class="hljs-selector-class">.marquee</span><span class="hljs-selector-pseudo">:hover</span> <span class="hljs-selector-class">.marquee__content</span> {
  <span class="hljs-attribute">animation-play-state</span>: paused;
}
</code></pre>
<p>And with that, it pauses on hover.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/03/04-Animated-marquee-that-pauses-on-hover.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Animated marquee that pauses on hover</em></p>
<ul>
<li><strong>Reverse on Double Tap:</strong> In the case where a user has passed important information and wants to see it without waiting for the looping animation to bring it back, it’s important to provide a means to achieve that.</li>
</ul>
<p>By double tapping on the component, the animation plays in the opposite direction, showing the information the user just passed. This feature not only promotes accessibility but also gives your web pages a snappy feel, as it provides a quicker way to get information.</p>
<p>To implement this, start by creating a reverse animation state.</p>
<pre><code class="lang-jsx"> <span class="hljs-keyword">const</span> [reverseAnimation, setReverseAnimation] = useState(<span class="hljs-literal">false</span>);
</code></pre>
<p>The create a function to flip the state of the animation.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> handleDoubleClick = <span class="hljs-function">() =&gt;</span> {
    setReverseAnimation(<span class="hljs-function">(<span class="hljs-params">prev</span>) =&gt;</span> !prev);
  };
</code></pre>
<p>After that, create the CSS class rule to reverse the animation.</p>
<pre><code class="lang-jsx"><span class="hljs-comment">/* Reverse animation */</span>
.marquee--reverse .marquee__content {
  animation-direction: reverse !important;
}
</code></pre>
<p>Then attach the handler function to the component.</p>
<pre><code class="lang-jsx">&lt;div className=<span class="hljs-string">"marquee"</span> onDoubleClick={handleDoubleClick}&gt;
      <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"marquee__content"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">" marquee__item"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{AndroidLogo}</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</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> <span class="hljs-attr">className</span>=<span class="hljs-string">" marquee__item"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{BehanceLogo}</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</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> <span class="hljs-attr">className</span>=<span class="hljs-string">" marquee__item"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{GoogleLogo}</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</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> <span class="hljs-attr">className</span>=<span class="hljs-string">" marquee__item"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{InstagramLogo}</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</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> <span class="hljs-attr">className</span>=<span class="hljs-string">" marquee__item"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{PaypalLogo}</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</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> <span class="hljs-attr">className</span>=<span class="hljs-string">" marquee__item"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{SpotifyLogo}</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</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">ul</span>&gt;</span></span>

      <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">aria-hidden</span>=<span class="hljs-string">"true"</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"marquee__content"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">" marquee__item"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{AndroidLogo}</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</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> <span class="hljs-attr">className</span>=<span class="hljs-string">" marquee__item"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{BehanceLogo}</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</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> <span class="hljs-attr">className</span>=<span class="hljs-string">" marquee__item"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{GoogleLogo}</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</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> <span class="hljs-attr">className</span>=<span class="hljs-string">" marquee__item"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{InstagramLogo}</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</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> <span class="hljs-attr">className</span>=<span class="hljs-string">" marquee__item"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{PaypalLogo}</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</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> <span class="hljs-attr">className</span>=<span class="hljs-string">" marquee__item"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{SpotifyLogo}</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</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">ul</span>&gt;</span></span>
&lt;/div&gt;
</code></pre>
<p>Finally, conditionally add the reverse class to the component which reverses the animation on double click.</p>
<pre><code class="lang-jsx"> &lt;div className={<span class="hljs-string">`marquee <span class="hljs-subst">${reverseAnimation &amp;&amp; <span class="hljs-string">"marquee--reverse"</span>}</span>`</span>} 
      onDoubleClick={handleDoubleClick}&gt;
</code></pre>
<p>Double-clicking the component now gives;</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/03/05-Animated-marquee-that-revereses-on-double-click.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Animated marquee that reverses on double click</em></p>
<ul>
<li><strong>Pause/Play on Space Bar Click</strong>: Another functionality that can be added to improve UX, especially for keyboard users is to pause or play it on press of the spacebar. This mimics the functionality of how videos work on the web and would help improve accessibility for users.</li>
</ul>
<p>To implement this, start by creating a state to store the current paused state of the animation.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> [isAnimationPaused, setIsAnimationPaused] = useState(<span class="hljs-literal">false</span>);
</code></pre>
<p>Then create the CSS rule for the paused state.</p>
<pre><code class="lang-jsx"><span class="hljs-comment">/* Pause animation */</span>
.marquee--paused .marquee__content {
  animation-play-state: paused !important;
}
</code></pre>
<p>After that, create an effect that updates the <code>isAnimationPaused</code> state each time the space bar is pressed.</p>
<pre><code class="lang-jsx"> useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> handleKeyPress = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
      <span class="hljs-keyword">if</span> (event.code === <span class="hljs-string">"Space"</span>) {

        setIsAnimationPaused(<span class="hljs-function">(<span class="hljs-params">prev</span>) =&gt;</span> !prev);
      }
    };
    <span class="hljs-built_in">document</span>.addEventListener(<span class="hljs-string">"keydown"</span>, handleKeyPress);

   <span class="hljs-comment">// Clean-up function when component unmounts</span>
    <span class="hljs-keyword">return</span> <span class="hljs-function">() =&gt;</span> {
      <span class="hljs-built_in">document</span>.removeEventListener(<span class="hljs-string">"keydown"</span>, handleKeyPress);
    };
  }, []);
</code></pre>
<p>This way, the state toggles between true and false based on user presses.<br>Finally, dynamically add the paused class to your component.</p>
<pre><code class="lang-jsx">&lt;div className={<span class="hljs-string">`marquee <span class="hljs-subst">${reverseAnimation &amp;&amp; <span class="hljs-string">"marquee--reverse"</span>}</span> <span class="hljs-subst">${
       isAnimationPaused &amp;&amp; <span class="hljs-string">"marquee--paused"</span>}</span>`</span>} onDoubleClick={handleDoubleClick}&gt;
</code></pre>
<p>And with that, your component pauses and replays each time you press the space bar.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/03/06-Animated-marquee-that-can-be-paused-with-space-bar.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Animated marquee that can be paused with space bar</em></p>
<h2 id="heading-best-practices-and-tips-for-marquee-component-development">Best Practices and Tips for Marquee Component Development</h2>
<p>Some of the best practices to consider when building this component includes:</p>
<ul>
<li><strong>Lazy Loading Images</strong>: In the case where your marquee has a lot of high-quality images which could be large, it is essential to optimize them before building the component.<br><a target="_blank" href="https://daiveedjay.hashnode.dev/implementing-image-lazy-loading-to-improve-website-performance-using-javascript">Lazy loading</a> defers the browser from downloading the images until they are needed (required to be shown in the viewport), cutting down on overall page load time.</li>
</ul>
<p>To achieve this, add <code>loading='lazy'</code> property to your images.</p>
<pre><code class="lang-jsx">&lt;ul className=<span class="hljs-string">"marquee__content"</span>&gt;
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">" marquee__item"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{AndroidLogo}</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</span> <span class="hljs-attr">loading</span>=<span class="hljs-string">"lazy"</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></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">" marquee__item"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{BehanceLogo}</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</span> <span class="hljs-attr">loading</span>=<span class="hljs-string">"lazy"</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></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">" marquee__item"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{GoogleLogo}</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</span> <span class="hljs-attr">loading</span>=<span class="hljs-string">"lazy"</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></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">" marquee__item"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{InstagramLogo}</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</span> <span class="hljs-attr">loading</span>=<span class="hljs-string">"lazy"</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></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">" marquee__item"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{PaypalLogo}</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</span> <span class="hljs-attr">loading</span>=<span class="hljs-string">"lazy"</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></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">" marquee__item"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{SpotifyLogo}</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</span> <span class="hljs-attr">loading</span>=<span class="hljs-string">"lazy"</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  &lt;/ul&gt;

  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">aria-hidden</span>=<span class="hljs-string">"true"</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"marquee__content"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">" marquee__item"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{AndroidLogo}</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</span> <span class="hljs-attr">loading</span>=<span class="hljs-string">"lazy"</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> <span class="hljs-attr">className</span>=<span class="hljs-string">" marquee__item"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{BehanceLogo}</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</span> <span class="hljs-attr">loading</span>=<span class="hljs-string">"lazy"</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> <span class="hljs-attr">className</span>=<span class="hljs-string">" marquee__item"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{GoogleLogo}</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</span> <span class="hljs-attr">loading</span>=<span class="hljs-string">"lazy"</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> <span class="hljs-attr">className</span>=<span class="hljs-string">" marquee__item"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{InstagramLogo}</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</span> <span class="hljs-attr">loading</span>=<span class="hljs-string">"lazy"</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> <span class="hljs-attr">className</span>=<span class="hljs-string">" marquee__item"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{PaypalLogo}</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</span> <span class="hljs-attr">loading</span>=<span class="hljs-string">"lazy"</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> <span class="hljs-attr">className</span>=<span class="hljs-string">" marquee__item"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{SpotifyLogo}</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</span> <span class="hljs-attr">loading</span>=<span class="hljs-string">"lazy"</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">ul</span>&gt;</span></span>
</code></pre>
<ul>
<li><strong>Mindful Animation Speed</strong>: When implementing the animation, it's crucial to strike a careful balance in terms of speed. The animation pace should be visually appealing, capturing the user's attention without sacrificing readability or causing discomfort.<br>This involves thoughtful consideration of how quickly the content scrolls across the screen.<br>By paying attention to animation speed and finding the right balance, you enhance the overall user experience, making it an effective and enjoyable element on your website.</li>
<li><strong>Think of Users with Motion Sensitivity</strong>: Inclusive design means taking into account the needs and preferences of different users, including those with motion sensitivity. Certain users may prefer less movement due to conditions such as vestibular disorders or simply for personal comfort.<br>To support these users, you can use the <code>prefers-reduced-motion</code> media query in your component.</li>
</ul>
<pre><code class="lang-jsx"><span class="hljs-comment">/* Pause animation when reduced-motion is set */</span>
@media (prefers-reduced-motion: reduce) {
  .marquee__content {
    animation-play-state: paused !important;
  }
}
</code></pre>
<ul>
<li><strong>Proper Documentation</strong>: Provide clear documentation on how users can use your component effectively so that they won't struggle to use it or don’t miss out on the all the features it has. Consider using labels around the component or a pop-up to convey short instructions on its use.</li>
</ul>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Your guide to React Marquee Components is complete! From planning to execution, you've dived into creating dynamic scrolling elements for your web projects.</p>
<p>Remember, this component is more than motion—it's an interactive story. Whether sharing crucial info, promoting events, or injecting dynamism, your marquee is a versatile addition to your toolkit.</p>
<p>But this journey is just the beginning. Adjust speeds, consider sensitivities, and adopt best practices to refine your marquee. Let creativity flow, and may your scrolling stories leave a lasting impact.</p>
<p>Prioritize user experience, experiment with enhancements, and let your development shine in the web landscape. Happy scrolling!</p>
<h3 id="heading-contact-information"><strong>Contact Information</strong></h3>
<p>Want to connect or contact me? Feel free to hit me up on the following:</p>
<ul>
<li>Twitter: <a target="_blank" href="https://twitter.com/JajaDavid8">@jajadavid8</a></li>
<li>LinkedIn: <a target="_blank" href="https://www.linkedin.com/in/david-jaja-8084251b4/">David Jaja</a></li>
<li>Email: Jajadavidjid@gmail.com</li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Use Bento Grids Design in Your Web Projects ]]>
                </title>
                <description>
                    <![CDATA[ I believe we may have all noticed the trend of meticulously organized web layouts reminiscent of Japanese bento boxes. These 'Bento Grids' have swiftly gained traction, offering a visually appealing and structurally cohesive way to present content on... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/bento-grids-in-web-design/</link>
                <guid isPermaLink="false">66bb88f4add24ba4273250de</guid>
                
                    <category>
                        <![CDATA[ CSS Grid ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Design ]]>
                    </category>
                
                    <category>
                        <![CDATA[ projects ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ David Jaja ]]>
                </dc:creator>
                <pubDate>Thu, 04 Apr 2024 10:06:39 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/04/Article-cover.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>I believe we may have all noticed the trend of meticulously organized web layouts reminiscent of Japanese bento boxes. These 'Bento Grids' have swiftly gained traction, offering a visually appealing and structurally cohesive way to present content online.</p>
<p>In this article, we'll delve into the origins, rise, and practical implementation of the bento grid trend, exploring how it intersects aesthetics with functionality in modern web design.</p>
<h3 id="heading-prerequisites">Prerequisites</h3>
<ul>
<li>Fundamentals of HTML and CSS (CSS Grid)</li>
<li>Basics of Web Design</li>
</ul>
<h2 id="heading-the-philosophy-behind-bento-grids">The Philosophy Behind Bento Grids</h2>
<p>The concept of bento grids traces back to the Japanese tradition of serving a variety of dishes in a single, segmented container known as a bento box. This method of presentation not only ensures a balanced meal but also pleases the eye with its organization and simplicity.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/Bento-Japenese.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Bento Japanese Box</em></p>
<p>Translated into web design, bento grids offer a similar experience: diverse content segmented into distinct areas, making it both accessible and aesthetically balanced.</p>
<p>The bento grid philosophy hinges on compartmentalization and organization. It creates a predictable rhythm that users can follow, reducing cognitive load and enhancing the overall user experience. The design's symmetry and order offers a sense of calm and control, appealing to users' desire for simplicity and structure amidst the chaos of the internet.</p>
<h2 id="heading-the-rise-of-bento-grids">The Rise of Bento Grids</h2>
<p>While the use of grids in design is not new, the specific trend of bento grids began to gain traction as designers sought to create more organized and mobile-responsive layouts. </p>
<p>Powerhouses like Apple use this design pattern in promotional videos for their products as well.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/Apple-mac-promotional-infographic.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Apple mac promotional infographic</em></p>
<p>The trend also saw a surge in popularity with the advent of CSS Grid Layout and the growing focus on minimalist design that doesn't sacrifice functionality for form.</p>
<p>Platforms that emphasize content, such as online magazines, educational sites, and portfolios, were among the early adopters of bento grids. Their adoption highlighted the grid's ability to present diverse content types in a harmonious layout, thereby improving navigation and readability.</p>
<h2 id="heading-examining-the-trend">Examining the Trend</h2>
<p>Clean lines, geometric shapes, and a clear space division often characterize modern bento grids. They usually consist of:</p>
<ul>
<li>The title of a feature</li>
<li>A short description of the feature</li>
<li>Some infographic or interactive content.</li>
</ul>
<p>This trend has been propelled by its positive impact on user experience. A well-implemented bento grid guides users through the website with ease, allowing quick access to information without overwhelming them with choices.</p>
<h2 id="heading-pros-of-using-bento-grids">Pros of Using Bento Grids</h2>
<ol>
<li><strong>Enhanced Organization and Cohesion</strong>: Bento grids bring a high level of organization to web design, allowing for a cohesive presentation of varied content. This segmentation makes it easier for users to digest information in a structured manner.</li>
<li><strong>Aesthetic Appeal</strong>: The symmetry and clean lines inherent in bento grids are visually appealing, providing a neat and professional look that can enhance the visual identity of a website.</li>
<li><strong>Reduced Scroll Fatigue</strong>: By efficiently utilizing space within a single viewport, bento grids can display a significant amount of content, which can reduce the need for excessive scrolling.</li>
<li><strong>Metaphorical Clarity</strong>: The bento box metaphor effectively communicates the concept of a complete and balanced experience, which can be particularly useful for showcasing product features or a portfolio of work.</li>
<li><strong>Improved Navigation</strong>: The predictability and order of bento grids aid in straightforward navigation, as users can easily move from one compartmentalized section to another.</li>
<li><strong>Compatibility with Responsive Design</strong>: Bento grids seamlessly integrate with responsive design principles, facilitating effortless adjustment of a website's layout to accommodate diverse screen sizes and devices.</li>
<li><strong>Focus on Content</strong>: The grid layout emphasizes content without unnecessary distractions, which can be crucial for sites where content is important, such as online galleries or information-driven platforms. </li>
<li><strong>Facilitates Comprehensive Product Capture</strong>: In the context of showcasing products, bento grids offer users the convenience of capturing all essential information at once. With content neatly organized within distinct compartments, users can easily screenshot or save a single view of the grid, ensuring they capture all relevant details without the need for multiple interactions or navigating through various pages.</li>
</ol>
<h2 id="heading-cons-of-bento-grids">Cons of Bento Grids</h2>
<ol>
<li><strong>Potential Information Overload</strong>: While bento grids can reduce cognitive load through organization, there's a risk of cramming too much information into a single screen, potentially overwhelming users.</li>
<li><strong>Limited Visual Hierarchy</strong>: The uniform structure of bento grids can sometimes lead to a lack of visual hierarchy, making it harder for users to determine the importance of certain content over others.</li>
<li><strong>Considerations Regarding Hick's Law</strong>: A densely packed grid presents users with a multitude of options, potentially prolonging their decision-making process. This abundance of choices can result in the paradox of choice, where <a target="_blank" href="https://lawsofux.com/hicks-law/">users experience indecision or slower navigation due to the overwhelming array of options available</a>.</li>
<li><strong>Design Rigidity</strong>: The structured nature of bento grids can sometimes restrict creative design elements and lead to a monotonous user experience if not implemented with variation and dynamic content.</li>
<li><strong>SEO Challenges</strong>: Search engines may have difficulty parsing the relevance of content when it's distributed across numerous grid compartments, potentially impacting SEO if not structured properly.</li>
<li><strong>Accessibility Concerns</strong>: The compartmentalized nature of bento grids might present accessibility challenges, particularly for users who rely on screen readers or keyboard navigation, if not designed with accessibility standards in mind.</li>
</ol>
<h2 id="heading-bento-grids-in-practice">Bento Grids in Practice</h2>
<p>Creating bento grids typically involves CSS grid layout and flexbox, which offer robust solutions for creating complex layouts with ease. Bento grids are favored for their flexibility and responsiveness, allowing content to reflow seamlessly across different screen sizes.</p>
<p>For this article, here’s the design we’re going to create the interface below:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/desktop-design-to-recreate.png" alt="Image" width="600" height="400" loading="lazy">
<em>desktop design to recreate</em></p>
<p>To begin, create a couple of <code>divs</code> in your markup.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"grid"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"item"</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> <span class="hljs-attr">class</span>=<span class="hljs-string">"item"</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> <span class="hljs-attr">class</span>=<span class="hljs-string">"item"</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> <span class="hljs-attr">class</span>=<span class="hljs-string">"item"</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> <span class="hljs-attr">class</span>=<span class="hljs-string">"item"</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 class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
</code></pre>
<p>Then utilize the <code>grid</code> property, <code>grid-template-columns</code>, and <code>grid-template-rows</code> to define the number of rows and columns you desire.</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.grid</span> {
  <span class="hljs-attribute">background</span>: <span class="hljs-built_in">hsl</span>(<span class="hljs-number">36</span>, <span class="hljs-number">100%</span>, <span class="hljs-number">99%</span>);
  <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
  <span class="hljs-attribute">max-width</span>: <span class="hljs-number">1500px</span>;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">1000px</span>;
  <span class="hljs-attribute">display</span>: grid;
  <span class="hljs-attribute">gap</span>: <span class="hljs-number">1.5vw</span>;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">1vw</span>;
  <span class="hljs-attribute">grid-template-columns</span>: <span class="hljs-built_in">repeat</span>(<span class="hljs-number">6</span>, <span class="hljs-number">1</span>fr);
  <span class="hljs-attribute">grid-template-rows</span>: auto;
}
</code></pre>
<p>The final ingredient to achieving a bento-style grid lies in the use of the <code>grid-template-areas</code> property which is used to name grid areas according to the position you want them to occupy on the page.</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.grid</span> {
  <span class="hljs-attribute">background</span>: <span class="hljs-built_in">hsl</span>(<span class="hljs-number">36</span>, <span class="hljs-number">100%</span>, <span class="hljs-number">99%</span>);
  <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
  <span class="hljs-attribute">max-width</span>: <span class="hljs-number">1500px</span>;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">1000px</span>;
  <span class="hljs-attribute">display</span>: grid;
  <span class="hljs-attribute">gap</span>: <span class="hljs-number">1.5vw</span>;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">1vw</span>;
  <span class="hljs-attribute">grid-template-columns</span>: <span class="hljs-built_in">repeat</span>(<span class="hljs-number">6</span>, <span class="hljs-number">1</span>fr);
  <span class="hljs-attribute">grid-template-rows</span>: auto;
  <span class="hljs-attribute">grid-template-areas</span>:
    <span class="hljs-string">"hero hero hero hero aside2 aside2"</span>
    <span class="hljs-string">"hero hero hero hero aside2 aside2"</span>
    <span class="hljs-string">"hero hero hero hero aside2 aside2"</span>
    <span class="hljs-string">"hero hero hero hero aside2 aside2"</span>
    <span class="hljs-string">"aside3 aside3 aside4 aside4 aside5 aside5 "</span>;
}
</code></pre>
<p>Finally, assign those names to the exact element you want to take up that space.</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.item</span> {
  <span class="hljs-attribute">border</span>: <span class="hljs-number">2px</span> solid <span class="hljs-number">#464545</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">5px</span>;
}

<span class="hljs-selector-class">.grid</span> <span class="hljs-selector-class">.item</span><span class="hljs-selector-pseudo">:nth-child(1)</span> {
  <span class="hljs-attribute">grid-area</span>: hero;
}
<span class="hljs-selector-class">.grid</span> <span class="hljs-selector-class">.item</span><span class="hljs-selector-pseudo">:nth-child(2)</span> {
  <span class="hljs-attribute">grid-area</span>: aside2;
}

<span class="hljs-selector-class">.grid</span> <span class="hljs-selector-class">.item</span><span class="hljs-selector-pseudo">:nth-child(3)</span> {
  <span class="hljs-attribute">grid-area</span>: aside3;
}
<span class="hljs-selector-class">.grid</span> <span class="hljs-selector-class">.item</span><span class="hljs-selector-pseudo">:nth-child(4)</span> {
  <span class="hljs-attribute">grid-area</span>: aside4;
}

<span class="hljs-selector-class">.grid</span> <span class="hljs-selector-class">.item</span><span class="hljs-selector-pseudo">:nth-child(5)</span> {
  <span class="hljs-attribute">grid-area</span>: aside5;
}
</code></pre>
<p>You should have this result:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/01-Bento-structure-achieved-.png" alt="Image" width="600" height="400" loading="lazy">
<em>Bento structure achieved</em></p>
<p>All that’s left is to fill the boxes with their appropriate content and assets. You can some assets/content in this <a target="_blank" href="https://github.com/Daiveedjay/Bento/tree/main/images">repo</a>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/02-Bento-with-content-filled.png" alt="Image" width="600" height="400" loading="lazy">
<em>Bento Grid with its content filled</em></p>
<p>Another usefulness of the <code>grid-template-areas</code> property is the ease by which you can achieve responsiveness with it. In our example, to make the page responsive, you pass in a new string pair on your preferred threshold.</p>
<p>On tablet screens:</p>
<pre><code class="lang-css"><span class="hljs-keyword">@media</span> screen <span class="hljs-keyword">and</span> (<span class="hljs-attribute">max-width:</span> <span class="hljs-number">1000px</span>) {
  <span class="hljs-selector-class">.grid</span> {
    <span class="hljs-attribute">grid-template-columns</span>: <span class="hljs-built_in">repeat</span>(<span class="hljs-number">4</span>, <span class="hljs-number">1</span>fr);
    <span class="hljs-attribute">grid-template-areas</span>:
      <span class="hljs-string">"hero   hero   hero   hero"</span>
      <span class="hljs-string">"hero   hero   hero   hero"</span>
      <span class="hljs-string">"aside2 aside2 aside2 aside3"</span>
      <span class="hljs-string">"aside4 aside4 aside5 aside5"</span>;
  }
}
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/03-Tablet-screens.png" alt="Image" width="600" height="400" loading="lazy">
<em>Tablet Screens</em></p>
<p>And on smaller screens:</p>
<pre><code class="lang-css"><span class="hljs-keyword">@media</span> screen <span class="hljs-keyword">and</span> (<span class="hljs-attribute">max-width:</span> <span class="hljs-number">750px</span>) {
  <span class="hljs-selector-class">.grid</span> {
    <span class="hljs-attribute">grid-template-columns</span>: <span class="hljs-built_in">repeat</span>(<span class="hljs-number">3</span>, <span class="hljs-number">1</span>fr);
    <span class="hljs-attribute">grid-template-areas</span>:
      <span class="hljs-string">"hero   hero   hero"</span>
      <span class="hljs-string">"hero   hero   hero"</span>
      <span class="hljs-string">"aside2 aside2 aside2"</span>
      <span class="hljs-string">"aside3 aside3 aside3"</span>
      <span class="hljs-string">"aside4 aside4 aside4"</span>
      <span class="hljs-string">"aside5 aside5 aside5"</span>;
  }
}
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/04-Smaller-screens.png" alt="Image" width="600" height="400" loading="lazy">
<em>Smaller screens</em></p>
<h2 id="heading-common-rules-of-bento-grids">Common Rules of Bento Grids</h2>
<p>Here are some good rules of thumb when building bento grids:</p>
<ul>
<li><strong>Group Related Content</strong>: One of the fundamental principles of bento grids is to group related content together within each segment. This enhances the user's ability to quickly locate and understand the information they're seeking. By organizing content logically, designers can improve user engagement and satisfaction.</li>
<li><strong>Vary Box Sizes</strong>: Avoid using the same size for every box within the grid. Varying box sizes can create visual interest and hierarchy, drawing attention to key elements while maintaining overall balance. This variation can help guide users through the content and highlight important information effectively.</li>
<li><strong>Establish Visual Hiererchy</strong>: Although varying box sizes contribute to visual hierarchy, establishing visual hierarchy encompasses a broader range of design elements. In addition to box sizes, designers should consider factors such as colour, typography, and placement to prioritize certain elements over others.</li>
<li><strong>Prioritize Center Square</strong>: In traditional bento grids, the center square often holds a special significance and acts as a focal point. Designers can use this central square to showcase critical information or highlight key features, effectively punctuating the grid and drawing users' attention to its core elements.</li>
<li><strong>Limit the Number of Boxes</strong>: To maintain clarity and avoid overwhelming users, it's recommended to use nine or fewer boxes within the bento grid. Limiting the number of boxes ensures that the layout remains manageable and facilitates easier navigation and comprehension for users.</li>
<li><strong>Consider Swirl Pattern</strong>: While not a strict rule, considering a swirl pattern can add an extra layer of visual interest to the bento grid design. This involves arranging content in a curved or swirling pattern within the grid, creating a dynamic and engaging layout that encourages exploration.</li>
</ul>
<h2 id="heading-additional-information">Additional Information</h2>
<p>I’d like to point out a couple of things in the article not highlighted.</p>
<ul>
<li>First and foremost, the article was inspired by <a target="_blank" href="https://x.com/itsdesignertom/status/1764856109754667243?s=20">Tom Geoco</a>’s video on bento grids.</li>
<li><a target="_blank" href="https://bentogrids.com/">BentoGrids</a> is an excellent resource for finding design inspiration if you’re interested. If you’re interested in the full code, here’s the repo, <a target="_blank" href="https://github.com/Daiveedjay/Bento">GitHub</a>, and the Live version. <a target="_blank" href="https://bentogrid.netlify.app/">Demo</a>.</li>
<li>The design inspiration for the grid we built was gotten from <a target="_blank" href="https://www.frontendmentor.io/challenges/news-homepage-H6SWTa1MFl">FrontEnd Mentor</a>.</li>
</ul>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Bento grids stand out as a significant trend in the modern web design landscape, offering a blend of aesthetic appeal and functional clarity. They represent a design ethos that values order, beauty, and user-centricity. </p>
<p>As web technologies evolve, the principles underlying bento grids will continue to inform best practices, encouraging designers to create experiences that are not only visually compelling but also intuitively navigable.</p>
<h3 id="heading-contact-information">Contact Information</h3>
<p>Want to connect or contact me? Feel free to hit me up on the following:</p>
<ul>
<li>Twitter / X: <a target="_blank" href="https://twitter.com/JajaDavid8">@jajadavid8</a></li>
<li>LinkedIn: <a target="_blank" href="https://www.linkedin.com/in/david-jaja-8084251b4/">David Jaja</a></li>
<li>Email: Jajadavidjid@gmail.com</li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ React Navigation – How to Build a Breadcrumb Component ]]>
                </title>
                <description>
                    <![CDATA[ I know what you're thinking – but despite the article title and cover image, this article isn't about bread or even pastries. Instead, it looks at a commonly used component in web applications for navigation called the breadcrumb component. Here, we'... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/react-navigation-build-a-breadcrumb-component/</link>
                <guid isPermaLink="false">66bb8914b0d3ac3d7acde3dd</guid>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ react-navigation ]]>
                    </category>
                
                    <category>
                        <![CDATA[ routing ]]>
                    </category>
                
                    <category>
                        <![CDATA[ tailwind ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ David Jaja ]]>
                </dc:creator>
                <pubDate>Mon, 25 Mar 2024 22:33:05 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/03/Breadcrumb-article-cover.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>I know what you're thinking – but despite the article title and cover image, this article isn't about bread or even pastries. Instead, it looks at a commonly used component in web applications for navigation called the breadcrumb component.</p>
<p>Here, we'll unravel the mysteries of breadcrumb trails in React applications. We'll dissect their types, and you'll learn how to seamlessly integrate them into your web projects for better user navigation.</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<ul>
<li>Fundamentals of CSS and TailwindCSS</li>
<li>Fundamentals of ES6 JavaScript and React </li>
<li>Fundamentals of Routing and the React Router library ( check out this <a target="_blank" href="https://www.freecodecamp.org/news/improve-user-experience-in-react-by-animating-routes-using-framer-motion/">routing article</a> if you’re unfamiliar).</li>
</ul>
<h2 id="heading-what-well-cover">What We'll Cover:</h2>
<ol>
<li><a class="post-section-overview" href="#heading-understanding-breadcrumbs">Understanding Breadcrumbs</a></li>
<li><a class="post-section-overview" href="#heading-types-of-breadcrumb-navigation">Types of Breadcrumb Navigation</a></li>
<li><a class="post-section-overview" href="#heading-how-to-build-the-breadcrumb-component-in-react">How to Build the Breadcrumb Component in React</a></li>
<li><a class="post-section-overview" href="#heading-how-to-create-the-breadcrumb-component-structure">How to Create the Breadcrumb Component Structure</a><br>– <a class="post-section-overview" href="#heading-location-based-breadcrumbs">Location-Based Breadcrumbs</a><br>– <a class="post-section-overview" href="#heading-path-based-breadcrumbs">Path-Based Breadcrumbs</a><br>– <a class="post-section-overview" href="#heading-attribute-based-breadcrumbs">Attribute-Based Breadcrumbs</a></li>
<li><a class="post-section-overview" href="#heading-best-practices-for-breadcrumbs-in-react">Best Practices for Breadcrumbs in React</a></li>
<li><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></li>
</ol>
<h2 id="heading-understanding-breadcrumbs">Understanding Breadcrumbs</h2>
<p>Before we venture deeper into the intricacies of breadcrumbs, let's set the scene. Imagine the classic tale of <a target="_blank" href="https://en.wikipedia.org/wiki/Hansel_and_Gretel">Hansel and Gretel</a>, where they leave a trail of breadcrumbs to find their way back home through the dense forest. </p>
<p>In the digital realm, breadcrumbs serve a similar purpose, albeit with a twist.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/03/Hansel-And-Gretel-2.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Hansel And Gretel</em></p>
<p>Breadcrumbs, in the context of web navigation, are a series of hierarchical links typically displayed at the top of a webpage. These links reflect the user's path from the homepage to the current page, allowing them to retrace their steps or navigate to higher-level pages.</p>
<p>These navigation aids have a fascinating history and a crucial role in guiding users through a digital space.</p>
<p>A typical example of what this component looks like is shown below:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/03/Breadcrumb-example.png" alt="Image" width="600" height="400" loading="lazy">
<em>Breadcrumb example: Home Page &gt; Products Page &gt; Single Product Page (current page)</em></p>
<h3 id="heading-types-of-breadcrumb-navigation">Types of Breadcrumb Navigation</h3>
<ul>
<li><strong>Location-based Breadcrumbs</strong>: Like landmarks in a forest, location-based breadcrumbs show users where they are within the website's hierarchy. They show the current page's position relative to other pages on the site.</li>
<li><strong>Path-based Breadcrumbs</strong>: Like retracing your steps in the forest, path-based breadcrumbs display the user's journey through the website. They show the sequence of pages visited, helping users understand how they arrived at the current page.</li>
<li><strong>Attribute-based Breadcrumbs</strong>: These breadcrumbs highlight specific attributes or characteristics of the current page. They offer more context to the user's navigation, akin to discovering unique features along a trail.</li>
</ul>
<h2 id="heading-how-to-build-the-breadcrumb-component-in-react">How to Build the Breadcrumb Component in React</h2>
<p>The first step in this section involves creating a React environment. Before you begin, make sure to install <a target="_blank" href="https://nodejs.org/en/download">Node.js</a> on your computer if you don't have it already.</p>
<h3 id="heading-how-to-set-up-a-react-environment">How to Set Up a React Environment</h3>
<p>After installing Node.js, use <a target="_blank" href="https://vitejs.dev/guide/">Vite</a> (a modern build tool for React projects) to create a new React project. In your local terminal, run the command:</p>
<pre><code class="lang-bash">npm create vite@latest
</code></pre>
<p>Select React as your framework and your preferred variant.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/03/Setting-up-a-react-environment-with-Vite.png" alt="Image" width="600" height="400" loading="lazy">
<em>Setting up a react environment with Vite</em></p>
<p>To install the necessary packages, run <code>npm install</code> and open it in your IDE.</p>
<p>Finally, clear the boilerplate code and start up your server using the command <code>npm run dev</code>.</p>
<p>This project will use Tailwind for styling. To get that set up, run the following command:</p>
<pre><code class="lang-bash">npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
</code></pre>
<p>After this command, a <code>tailwind.config.js</code> file will be created. Head into the config file, delete its content, and paste this in there instead:</p>
<pre><code class="lang-js"><span class="hljs-comment">/** <span class="hljs-doctag">@type <span class="hljs-type">{import('tailwindcss').Config}</span> </span>*/</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
  <span class="hljs-attr">content</span>: [
    <span class="hljs-string">"./index.html"</span>,
    <span class="hljs-string">"./src/**/*.{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>Then, open your <code>index.css</code> file and paste the style configs (preferably at the top):</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>Finally, restart your dev server to get access to Tailwind.</p>
<h2 id="heading-how-to-create-the-breadcrumb-component-structure">How to Create the Breadcrumb Component Structure</h2>
<p>Rather than building one breadcrumb component, we’re going to build all three types mentioned above so you can see how they work.</p>
<h3 id="heading-location-based-breadcrumbs">Location-Based Breadcrumbs</h3>
<p>This type is the most basic type of breadcrumb that involves showing all the routes readily available for the user to navigate.</p>
<p>To begin, start by creating a Breadcrumb file and pasting in these styles:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> SlashImg <span class="hljs-keyword">from</span> <span class="hljs-string">"./assets/slash.png"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Breadcrumb</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">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-white "</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">className</span>=<span class="hljs-string">" flex border p-2 gap-6 text-xl text-[#2E4053] items-center"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">className</span>=<span class="hljs-string">" cursor-pointer hover:bg-[#E8DAEF] p-4 rounded-md"</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">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{SlashImg}</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"w-5 h-5 "</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">className</span>=<span class="hljs-string">" cursor-pointer hover:bg-[#E8DAEF] p-4 rounded-md transition-all duration-300"</span>&gt;</span>
          Products
        <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{SlashImg}</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"w-5 h-5 "</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">className</span>=<span class="hljs-string">" cursor-pointer hover:bg-[#E8DAEF] p-4 rounded-md transition-all duration-300"</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">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{SlashImg}</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"w-5 h-5 "</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">className</span>=<span class="hljs-string">" cursor-pointer hover:bg-[#E8DAEF] p-4 rounded-md transition-all duration-300"</span>&gt;</span>
          FAQ
        <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>
  );
}
</code></pre>
<p>Then import this file into a <code>Home</code> component which you also need to create:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> Breadcrumb <span class="hljs-keyword">from</span> <span class="hljs-string">"./Breadcrumb"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Home</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">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">" h-[100dvh] bg-gray-200"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex flex-col items-center gap-8 "</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">className</span>=<span class="hljs-string">" text-4xl text-[#2E4053 ] mt-20"</span>&gt;</span>
          My Breadcrumb Component 🍞
        <span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Breadcrumb</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>
  );
}
</code></pre>
<p>At the moment, your component looks like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/03/Breadcrumb-after-rendering-on-UI.png" alt="Image" width="600" height="400" loading="lazy">
<em>Breadcrumb after rendering on UI</em></p>
<p>To perform navigation functionalities with this component, start by installing <a target="_blank" href="https://www.npmjs.com/package/react-router-dom">React Router</a> (a widely used library for managing navigation and routing in React applications).</p>
<pre><code class="lang-bash">npm i react-router-dom
</code></pre>
<p>Then create the routes in your App component.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> { BrowserRouter, Navigate, Route, Routes } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-router-dom"</span>;

<span class="hljs-keyword">import</span> About <span class="hljs-keyword">from</span> <span class="hljs-string">"./About"</span>;
<span class="hljs-keyword">import</span> FAQ <span class="hljs-keyword">from</span> <span class="hljs-string">"./FAQ"</span>;
<span class="hljs-keyword">import</span> Home <span class="hljs-keyword">from</span> <span class="hljs-string">"./Home"</span>;
<span class="hljs-keyword">import</span> Homepage <span class="hljs-keyword">from</span> <span class="hljs-string">"./Homepage"</span>;
<span class="hljs-keyword">import</span> Products <span class="hljs-keyword">from</span> <span class="hljs-string">"./Products"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</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">BrowserRouter</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">index</span> <span class="hljs-attr">element</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">Navigate</span> <span class="hljs-attr">replace</span> <span class="hljs-attr">to</span>=<span class="hljs-string">"home"</span> /&gt;</span>} /&gt;
        <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">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"home"</span> <span class="hljs-attr">element</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">Homepage</span> /&gt;</span>} /&gt;
          <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"products"</span> <span class="hljs-attr">element</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">Products</span> /&gt;</span>} /&gt;
          <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"about"</span> <span class="hljs-attr">element</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">About</span> /&gt;</span>} /&gt;
          <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"faq"</span> <span class="hljs-attr">element</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">FAQ</span> /&gt;</span>} /&gt;
        <span class="hljs-tag">&lt;/<span class="hljs-name">Route</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">BrowserRouter</span>&gt;</span></span>
  );
}
</code></pre>
<p>The code block above is a configuration for client-side routing in a React application using React Router v6. It sets up a <code>BrowserRouter</code> to handle dynamic routing and defines a series of Route components within Routes to map URL paths to React components.</p>
<ul>
<li><code>BrowserRouter</code> is a router implementation that uses the HTML5 history API to keep the UI in sync with the URL.</li>
<li><code>Navigate</code> redirects users to a specific route. In this case, it redirects from the index route to <code>/home</code>.</li>
<li><code>Route</code> components define a mapping between a path and a component. The <code>element</code> prop specifies what to render when the path matches the current URL.</li>
<li>The <code>path="/" element={&lt;Home /&gt;}</code> route is a nested route that serves as a layout for its child routes. It renders the Home component when the URL is <code>/</code>. Nested inside the <code>Home</code> route are routes for <code>home</code>, <code>products</code>, <code>about</code>, and <code>faq</code>, each rendering their respective components when their path matches the URL.</li>
</ul>
<p>Next, head over to your Breadcrumb component and change the list elements to <code>Link</code> elements (imported from React Router) to aid routing between routes.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> { Link } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-router-dom"</span>;
<span class="hljs-keyword">import</span> SlashImg <span class="hljs-keyword">from</span> <span class="hljs-string">"./assets/slash.png"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Breadcrumb</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">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-white "</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">className</span>=<span class="hljs-string">" flex border p-2 gap-6 text-xl text-[#2E4053] items-center"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Link</span>
          <span class="hljs-attr">to</span>=<span class="hljs-string">{</span>"<span class="hljs-attr">home</span>"}
          <span class="hljs-attr">className</span>=<span class="hljs-string">" cursor-pointer hover:bg-[#E8DAEF] p-4 rounded-md"</span>&gt;</span>
          Home
        <span class="hljs-tag">&lt;/<span class="hljs-name">Link</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{SlashImg}</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"w-5 h-5 "</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Link</span>
          <span class="hljs-attr">to</span>=<span class="hljs-string">{</span>"<span class="hljs-attr">products</span>"}
          <span class="hljs-attr">className</span>=<span class="hljs-string">" cursor-pointer hover:bg-[#E8DAEF] p-4 rounded-md transition-all duration-300"</span>&gt;</span>
          Products
        <span class="hljs-tag">&lt;/<span class="hljs-name">Link</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{SlashImg}</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"w-5 h-5 "</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Link</span>
          <span class="hljs-attr">to</span>=<span class="hljs-string">{</span>"<span class="hljs-attr">about</span>"}
          <span class="hljs-attr">className</span>=<span class="hljs-string">" cursor-pointer hover:bg-[#E8DAEF] p-4 rounded-md transition-all duration-300"</span>&gt;</span>
          About
        <span class="hljs-tag">&lt;/<span class="hljs-name">Link</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{SlashImg}</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"w-5 h-5 "</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Link</span>
          <span class="hljs-attr">to</span>=<span class="hljs-string">{</span>"<span class="hljs-attr">faq</span>"}
          <span class="hljs-attr">className</span>=<span class="hljs-string">" cursor-pointer hover:bg-[#E8DAEF] p-4 rounded-md transition-all duration-300"</span>&gt;</span>
          FAQ
        <span class="hljs-tag">&lt;/<span class="hljs-name">Link</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>
  );
}
</code></pre>
<p>Then use the <code>Outlet</code> component provided by React Router to display the content of each route in the <code>Home</code> component.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> Breadcrumb <span class="hljs-keyword">from</span> <span class="hljs-string">"./Breadcrumb"</span>;
<span class="hljs-keyword">import</span> { Outlet } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-router-dom"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Home</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">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">" h-[100dvh] bg-gray-200"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex flex-col items-center gap-8 "</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">className</span>=<span class="hljs-string">" text-4xl text-[#2E4053 ] mt-20"</span>&gt;</span>
          My Breadcrumb Component 🍞
        <span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Breadcrumb</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Outlet</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>
  );
}
</code></pre>
<p>Testing out your component in the browser now gives the following result:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/03/Routing-with-the-Breadcrumb-component.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Routing with the Breadcrumb component</em></p>
<p>With this, your location-based breadcrumbs are functional, but we can take it a step further. To improve the UX, we can add an active class to the currently active route, creating a visual indicator of where the user is at every point in time.</p>
<p>Start by extracting the current location of the user in the Breadcrumb component:</p>
<pre><code class="lang-jsx">  <span class="hljs-keyword">const</span> location = useLocation();
</code></pre>
<p>Then use the pathname property to add an active class to each link:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> { Link, useLocation } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-router-dom"</span>;

<span class="hljs-keyword">import</span> SlashImg <span class="hljs-keyword">from</span> <span class="hljs-string">"./assets/slash.png"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Breadcrumb</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> location = useLocation();
  <span class="hljs-built_in">console</span>.log(location.pathname);

  <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">"bg-white "</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">className</span>=<span class="hljs-string">" flex border p-2 gap-6 text-xl text-[#2E4053] items-center"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Link</span>
          <span class="hljs-attr">to</span>=<span class="hljs-string">{</span>"<span class="hljs-attr">home</span>"}
          <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">cursor-pointer</span> <span class="hljs-attr">hover:bg-</span>[#<span class="hljs-attr">E8DAEF</span>] <span class="hljs-attr">p-4</span> <span class="hljs-attr">rounded-md</span> ${
            <span class="hljs-attr">location.pathname</span> === <span class="hljs-string">"/home"</span> &amp;&amp; "<span class="hljs-attr">bg-</span>[#<span class="hljs-attr">b572d6</span>] <span class="hljs-attr">text-white</span>"
          }`}&gt;</span>
          Home
        <span class="hljs-tag">&lt;/<span class="hljs-name">Link</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{SlashImg}</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"w-5 h-5 "</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Link</span>
          <span class="hljs-attr">to</span>=<span class="hljs-string">{</span>"<span class="hljs-attr">products</span>"}
          <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">cursor-pointer</span> <span class="hljs-attr">hover:bg-</span>[#<span class="hljs-attr">E8DAEF</span>] <span class="hljs-attr">p-4</span> <span class="hljs-attr">rounded-md</span> ${
            <span class="hljs-attr">location.pathname</span> === <span class="hljs-string">"/products"</span> &amp;&amp; "<span class="hljs-attr">bg-</span>[#<span class="hljs-attr">b572d6</span>] <span class="hljs-attr">text-white</span>"
          }`}&gt;</span>
          Products
        <span class="hljs-tag">&lt;/<span class="hljs-name">Link</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{SlashImg}</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"w-5 h-5 "</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Link</span>
          <span class="hljs-attr">to</span>=<span class="hljs-string">{</span>"<span class="hljs-attr">about</span>"}
          <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">cursor-pointer</span> <span class="hljs-attr">hover:bg-</span>[#<span class="hljs-attr">E8DAEF</span>] <span class="hljs-attr">p-4</span> <span class="hljs-attr">rounded-md</span> ${
            <span class="hljs-attr">location.pathname</span> === <span class="hljs-string">"/about"</span> &amp;&amp; "<span class="hljs-attr">bg-</span>[#<span class="hljs-attr">b572d6</span>] <span class="hljs-attr">text-white</span>"
          }`}&gt;</span>
          About
        <span class="hljs-tag">&lt;/<span class="hljs-name">Link</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{SlashImg}</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"w-5 h-5 "</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Link</span>
          <span class="hljs-attr">to</span>=<span class="hljs-string">{</span>"<span class="hljs-attr">faq</span>"}
          <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">cursor-pointer</span> <span class="hljs-attr">hover:bg-</span>[#<span class="hljs-attr">E8DAEF</span>] <span class="hljs-attr">p-4</span> <span class="hljs-attr">rounded-md</span> ${
            <span class="hljs-attr">location.pathname</span> === <span class="hljs-string">"/faq"</span> &amp;&amp; "<span class="hljs-attr">bg-</span>[#<span class="hljs-attr">b572d6</span>] <span class="hljs-attr">text-white</span>"
          }`}&gt;</span>
          FAQ
        <span class="hljs-tag">&lt;/<span class="hljs-name">Link</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>
  );
}
</code></pre>
<p>This now gives the following result:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/03/Routing-with-the-Breadcrumb-component-after-adding-an-active-class.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Routing with the Breadcrumb component after adding an active class</em></p>
<p>Tasty! 🍩</p>
<h3 id="heading-path-based-breadcrumbs">Path-Based Breadcrumbs</h3>
<p>This breadcrumb type uses the pattern of progressive reveal to better guide the users on where they are based on their actions.</p>
<p>Here we’re going to create two routes and move from the first to the third (Home to Single product page).</p>
<p>Start by modifying your <code>Home</code> component a bit.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Home</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">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">" h-[100dvh] bg-gray-200"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex flex-col items-center gap-8 "</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">className</span>=<span class="hljs-string">" text-4xl text-[#2E4053 ] mt-20"</span>&gt;</span>
          My Breadcrumb Component 🍞
        <span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Breadcrumb</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Outlet</span> /&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex gap-4 p-2 "</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">Link</span> <span class="hljs-attr">to</span>=<span class="hljs-string">"products"</span> <span class="hljs-attr">className</span>=<span class="hljs-string">" rounded-md p-2 bg-[#777] text-white"</span>&gt;</span>
            Products
          <span class="hljs-tag">&lt;/<span class="hljs-name">Link</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">Link</span>
            <span class="hljs-attr">to</span>=<span class="hljs-string">"products/1"</span>
            <span class="hljs-attr">className</span>=<span class="hljs-string">" rounded-md p-2 bg-[#777] text-white"</span>&gt;</span>
            Single Product
          <span class="hljs-tag">&lt;/<span class="hljs-name">Link</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 class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<p>The changes include creating a single product page which we'll route to later.</p>
<p>Then make a nested route path for the page in the App component:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> { BrowserRouter, Navigate, Route, Routes } <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">"./Home"</span>;
<span class="hljs-keyword">import</span> Homepage <span class="hljs-keyword">from</span> <span class="hljs-string">"./Homepage"</span>;
<span class="hljs-keyword">import</span> Products <span class="hljs-keyword">from</span> <span class="hljs-string">"./Products"</span>;
<span class="hljs-keyword">import</span> SingleProduct <span class="hljs-keyword">from</span> <span class="hljs-string">"./SingleProduct"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</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">BrowserRouter</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">index</span> <span class="hljs-attr">element</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">Navigate</span> <span class="hljs-attr">replace</span> <span class="hljs-attr">to</span>=<span class="hljs-string">"home"</span> /&gt;</span>} /&gt;
        <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">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"home"</span> <span class="hljs-attr">element</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">Homepage</span> /&gt;</span>} /&gt;
          <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"products"</span> <span class="hljs-attr">element</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">Products</span> /&gt;</span>}&gt;
            <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">":productId"</span> <span class="hljs-attr">element</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">SingleProduct</span> /&gt;</span>} /&gt;
          <span class="hljs-tag">&lt;/<span class="hljs-name">Route</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">Route</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">BrowserRouter</span>&gt;</span></span>
  );
}
</code></pre>
<p>For the already existing Products page, add these styles and changes:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> { Outlet } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-router-dom"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Products</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">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-[#EDBB99] p-2 w-96 h-96 flex flex-col items-center"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Products Page<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Outlet</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/03/Page-after-creating-the-Single-Product-page-without-any-routing-1.png" alt="Image" width="600" height="400" loading="lazy">
<em>Page after creating the Single Product page without any routing</em></p>
<p>Finally, modify your breadcrumb component to display the routes when you route to them from the home page.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> { Link, useLocation } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-router-dom"</span>;

<span class="hljs-keyword">import</span> RightArrowImg <span class="hljs-keyword">from</span> <span class="hljs-string">"./assets/right-icon.png"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Breadcrumb</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> location = useLocation();

  <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">"bg-white "</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">className</span>=<span class="hljs-string">" flex border p-2 gap-6 text-xl text-[#2E4053] items-center"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Link</span>
          <span class="hljs-attr">to</span>=<span class="hljs-string">{</span>"<span class="hljs-attr">home</span>"}
          <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">cursor-pointer</span> <span class="hljs-attr">hover:bg-</span>[#<span class="hljs-attr">E8DAEF</span>] <span class="hljs-attr">hover:text-black</span> <span class="hljs-attr">p-4</span> <span class="hljs-attr">rounded-md</span> ${
            <span class="hljs-attr">location.pathname</span> === <span class="hljs-string">"/home"</span> &amp;&amp; "<span class="hljs-attr">bg-</span>[#<span class="hljs-attr">b572d6</span>] <span class="hljs-attr">text-white</span>"
          }`}&gt;</span>
          Home
        <span class="hljs-tag">&lt;/<span class="hljs-name">Link</span>&gt;</span>
        {location.pathname.includes("/products") &amp;&amp; (
          <span class="hljs-tag">&lt;&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{RightArrowImg}</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"w-5 h-5 "</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</span> /&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">Link</span>
              <span class="hljs-attr">to</span>=<span class="hljs-string">{</span>"<span class="hljs-attr">products</span>"}
              <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>` <span class="hljs-attr">hover:text-black</span> <span class="hljs-attr">cursor-pointer</span> <span class="hljs-attr">hover:bg-</span>[#<span class="hljs-attr">E8DAEF</span>] <span class="hljs-attr">p-4</span> <span class="hljs-attr">rounded-md</span> ${
                <span class="hljs-attr">location.pathname.includes</span>("/<span class="hljs-attr">products</span>") &amp;&amp;
                " <span class="hljs-attr">bg-</span>[#<span class="hljs-attr">b572d6</span>] <span class="hljs-attr">text-white</span>"
              } ${
                <span class="hljs-attr">location.pathname.includes</span>("/<span class="hljs-attr">products</span>/") &amp;&amp;
                " <span class="hljs-attr">bg-</span>[#<span class="hljs-attr">E8DAEF</span>] <span class="hljs-attr">text-black</span>"
              }`}&gt;</span>
              Products
            <span class="hljs-tag">&lt;/<span class="hljs-name">Link</span>&gt;</span>
          <span class="hljs-tag">&lt;/&gt;</span>
        )}
        {location.pathname.includes(`/products/`) &amp;&amp; (
          <span class="hljs-tag">&lt;&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{RightArrowImg}</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"w-5 h-5 "</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</span> /&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">Link</span>
              <span class="hljs-attr">to</span>=<span class="hljs-string">{</span>"<span class="hljs-attr">products</span>"}
              <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">hover:text-black</span>  <span class="hljs-attr">cursor-pointer</span> <span class="hljs-attr">hover:bg-</span>[#<span class="hljs-attr">E8DAEF</span>] <span class="hljs-attr">p-4</span> <span class="hljs-attr">rounded-md</span> ${
                <span class="hljs-attr">location.pathname.includes</span>("/<span class="hljs-attr">products</span>") &amp;&amp;
                "<span class="hljs-attr">bg-</span>[#<span class="hljs-attr">b572d6</span>] <span class="hljs-attr">text-white</span>"
              }`}&gt;</span>
              Single Product
            <span class="hljs-tag">&lt;/<span class="hljs-name">Link</span>&gt;</span>
          <span class="hljs-tag">&lt;/&gt;</span></span>
        )}
      &lt;/ul&gt;
    &lt;/div&gt;
  );
}
</code></pre>
<p>In the code above, we’re displaying more breadcrumbs based on the route we’re in and applying styles to reflect the route changes.</p>
<p>Testing our component now gives the following result:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/03/Routing-with-the-Breadcrumb-component-after-adding-a-nested-route.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Routing with the Breadcrumb component after adding a nested route</em></p>
<p>Sweet! 🍬</p>
<h3 id="heading-attribute-based-breadcrumbs">Attribute-Based Breadcrumbs</h3>
<p>Attribute-based breadcrumbs focus on highlighting specific attributes or characteristics of the current page, such as tags, categories, or any other relevant metadata.</p>
<p>Instead of simply showing the user's path through the website hierarchy, they provide additional context that can aid in navigation and understanding. </p>
<p>A common use case for them is on E-commerce sites where you go through multiple items and filter through multiple product properties to find your desired product.</p>
<p>To begin, our app component is going to look drastically different with no routing done.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> Products <span class="hljs-keyword">from</span> <span class="hljs-string">"./Products"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</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">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">" h-[100dvh] bg-[#EDBB99]"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Products</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<p>Then add this JSX to your <code>Products</code> component:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> Breadcrumb <span class="hljs-keyword">from</span> <span class="hljs-string">"./Breadcrumb"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Products</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> dogsArray = [
    {
      <span class="hljs-attr">size</span>: <span class="hljs-string">"S"</span>,
      <span class="hljs-attr">color</span>: <span class="hljs-string">"white"</span>,
      <span class="hljs-attr">image</span>: <span class="hljs-string">"/small-white-dog.jpg"</span>,
      <span class="hljs-attr">name</span>: <span class="hljs-string">"Gigi"</span>,
      <span class="hljs-attr">age</span>: <span class="hljs-number">1</span>,
    },
    {
      <span class="hljs-attr">size</span>: <span class="hljs-string">"M"</span>,
      <span class="hljs-attr">color</span>: <span class="hljs-string">"white"</span>,
      <span class="hljs-attr">image</span>: <span class="hljs-string">"/medium-white-dog.jpg"</span>,
      <span class="hljs-attr">name</span>: <span class="hljs-string">"Tom"</span>,
      <span class="hljs-attr">age</span>: <span class="hljs-number">2</span>,
    },
    {
      <span class="hljs-attr">size</span>: <span class="hljs-string">"L"</span>,
      <span class="hljs-attr">color</span>: <span class="hljs-string">"white"</span>,
      <span class="hljs-attr">image</span>: <span class="hljs-string">"/big-white-dog.jpg"</span>,
      <span class="hljs-attr">name</span>: <span class="hljs-string">"Jake"</span>,
      <span class="hljs-attr">age</span>: <span class="hljs-number">3</span>,
    },
    {
      <span class="hljs-attr">size</span>: <span class="hljs-string">"S"</span>,
      <span class="hljs-attr">color</span>: <span class="hljs-string">"black"</span>,
      <span class="hljs-attr">image</span>: <span class="hljs-string">"/small-black-dog.jpg"</span>,
      <span class="hljs-attr">name</span>: <span class="hljs-string">"Hill"</span>,
      <span class="hljs-attr">age</span>: <span class="hljs-number">1</span>,
    },
    {
      <span class="hljs-attr">size</span>: <span class="hljs-string">"M"</span>,
      <span class="hljs-attr">color</span>: <span class="hljs-string">"black"</span>,
      <span class="hljs-attr">image</span>: <span class="hljs-string">"/medium-black-dog.jpg"</span>,
      <span class="hljs-attr">name</span>: <span class="hljs-string">"Jack"</span>,
      <span class="hljs-attr">age</span>: <span class="hljs-number">2</span>,
    },
    {
      <span class="hljs-attr">size</span>: <span class="hljs-string">"L"</span>,
      <span class="hljs-attr">color</span>: <span class="hljs-string">"black"</span>,
      <span class="hljs-attr">image</span>: <span class="hljs-string">"/big-black-dog.jpg"</span>,
      <span class="hljs-attr">name</span>: <span class="hljs-string">"Jones"</span>,
      <span class="hljs-attr">age</span>: <span class="hljs-number">3</span>,
    },
    {
      <span class="hljs-attr">size</span>: <span class="hljs-string">"S"</span>,
      <span class="hljs-attr">color</span>: <span class="hljs-string">"brown"</span>,
      <span class="hljs-attr">image</span>: <span class="hljs-string">"/small-brown-dog.jpg"</span>,
      <span class="hljs-attr">name</span>: <span class="hljs-string">"Herbert"</span>,
      <span class="hljs-attr">age</span>: <span class="hljs-number">1</span>,
    },
    {
      <span class="hljs-attr">size</span>: <span class="hljs-string">"M"</span>,
      <span class="hljs-attr">color</span>: <span class="hljs-string">"brown"</span>,
      <span class="hljs-attr">image</span>: <span class="hljs-string">"/medium-brown-dog.jpg"</span>,
      <span class="hljs-attr">name</span>: <span class="hljs-string">"Coco"</span>,
      <span class="hljs-attr">age</span>: <span class="hljs-number">2</span>,
    },
    {
      <span class="hljs-attr">size</span>: <span class="hljs-string">"L"</span>,
      <span class="hljs-attr">color</span>: <span class="hljs-string">"brown"</span>,
      <span class="hljs-attr">image</span>: <span class="hljs-string">"/big-brown-dog.jpg"</span>,
      <span class="hljs-attr">name</span>: <span class="hljs-string">"Benny"</span>,
      <span class="hljs-attr">age</span>: <span class="hljs-number">3</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">"flex flex-col items-center p-2"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"p-4"</span>&gt;</span>Adopt Page<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Breadcrumb</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">main</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"relative grid grid-cols-5 gap-6"</span>&gt;</span>
          {dogsArray.map((dog) =&gt; (
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{dog.name}</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">" w-[225px] rounded-md overflow-hidden"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"w-full "</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{dog.image}</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</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> <span class="hljs-attr">className</span>=<span class="hljs-string">"grid items-center grid-cols-2 gap-2 mt-2"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex items-center gap-2"</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>Name:<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-center text-white bg-orange-900 border rounded-[4px] p-1.5 min-w-14"</span>&gt;</span>
                    {dog.name}
                  <span class="hljs-tag">&lt;/<span class="hljs-name">p</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> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex gap-2 "</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>Size:<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-center text-white min-w-14"</span>&gt;</span>{dog.size}<span class="hljs-tag">&lt;/<span class="hljs-name">p</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> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex gap-2 "</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>Color:<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-center text-white capitalize min-w-14"</span>&gt;</span>
                    {dog.color}
                  <span class="hljs-tag">&lt;/<span class="hljs-name">p</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> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex gap-2 "</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>Age:<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-center text-white min-w-14"</span>&gt;</span>
                    {`${dog.age + " " + "year"}${dog.age &gt; 1 ? "s" : ""}`}
                  <span class="hljs-tag">&lt;/<span class="hljs-name">p</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 class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
          ))}

          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"absolute bottom-0 left-0 p-1 translate-y-[110%]"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mb-2"</span>&gt;</span>Filter by<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex items-center mb-4"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">h3</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"w-12"</span>&gt;</span>Size:<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex gap-2"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
                  <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">p-2</span> <span class="hljs-attr">text-center</span> <span class="hljs-attr">bg-white</span> <span class="hljs-attr">rounded-md</span> <span class="hljs-attr">min-w-14</span> `}&gt;</span>
                  All
                <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
                  <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">p-2</span> <span class="hljs-attr">text-center</span> <span class="hljs-attr">bg-white</span> <span class="hljs-attr">rounded-md</span> <span class="hljs-attr">min-w-14</span> `}&gt;</span>
                  S
                <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
                  <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">p-2</span> <span class="hljs-attr">text-center</span> <span class="hljs-attr">bg-white</span> <span class="hljs-attr">rounded-md</span> <span class="hljs-attr">min-w-14</span> `}&gt;</span>
                  M
                <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
                  <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">p-2</span> <span class="hljs-attr">text-center</span> <span class="hljs-attr">bg-white</span> <span class="hljs-attr">rounded-md</span> <span class="hljs-attr">min-w-14</span> `}&gt;</span>
                  L
                <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex items-center"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">h3</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"w-12"</span>&gt;</span>Color:<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex gap-2"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
                  <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">p-2</span> <span class="hljs-attr">text-center</span> <span class="hljs-attr">bg-white</span>  <span class="hljs-attr">rounded-md</span> <span class="hljs-attr">min-w-14</span> `}&gt;</span>
                  All
                <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
                  <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">p-2</span> <span class="hljs-attr">text-center</span> <span class="hljs-attr">bg-white</span>  <span class="hljs-attr">rounded-md</span> <span class="hljs-attr">min-w-14</span>`}&gt;</span>
                  White
                <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
                  <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">p-2</span> <span class="hljs-attr">text-center</span> <span class="hljs-attr">rounded-md</span> <span class="hljs-attr">bg-white</span> <span class="hljs-attr">min-w-14</span> `}&gt;</span>
                  Brown
                <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
                  <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">p-2</span> <span class="hljs-attr">text-center</span> <span class="hljs-attr">rounded-md</span> <span class="hljs-attr">bg-white</span>  <span class="hljs-attr">min-w-14</span> `}&gt;</span>
                  Black
                <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</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 class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<p>This JSX uses dummy dog data to create a template and style it with tailwind.</p>
<p>At the moment, your app should look like this;</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/03/Page-after-looping-over-the-dummy-dog-data.png" alt="Image" width="600" height="400" loading="lazy">
<em>Page after looping over the dummy dog data</em></p>
<p>To implement the attribute-based breadcrumbs, start by creating two states for the attributes you want to filter by:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> [sizeFilter, setSizeFilter] = useState(<span class="hljs-literal">null</span>);
<span class="hljs-keyword">const</span> [colorFilter, setColorFilter] = useState(<span class="hljs-literal">null</span>);
</code></pre>
<p>Then create a function to filter based on the value passed in:</p>
<pre><code class="lang-jsx">  <span class="hljs-keyword">const</span> filteredDogs = dogsArray.filter(<span class="hljs-function">(<span class="hljs-params">dog</span>) =&gt;</span> {
    <span class="hljs-keyword">if</span> (sizeFilter &amp;&amp; dog.size !== sizeFilter) <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;

    <span class="hljs-keyword">if</span> (colorFilter &amp;&amp; dog.color !== colorFilter) <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;

    <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
  });
</code></pre>
<p>After that, change the array you used used to create the JSX to the array returned from the function:</p>
<pre><code class="lang-jsx"> {filteredDogs.map(<span class="hljs-function">(<span class="hljs-params">dog</span>) =&gt;</span> (
            <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{dog.name}</span>&gt;</span></span>
</code></pre>
<p>Finally, use the setter function to pass in the values you want to filter by:</p>
<pre><code class="lang-jsx">&lt;main&gt;
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"relative grid grid-cols-5 gap-6"</span>&gt;</span>
          {filteredDogs.map((dog) =&gt; (
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{dog.name}</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">" w-[225px] rounded-md overflow-hidden"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"w-full "</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{dog.image}</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</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> <span class="hljs-attr">className</span>=<span class="hljs-string">"grid items-center grid-cols-2 gap-2 mt-2"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex items-center gap-2"</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>Name:<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-center text-white bg-orange-900 border rounded-[4px] p-1.5 min-w-14"</span>&gt;</span>
                    {dog.name}
                  <span class="hljs-tag">&lt;/<span class="hljs-name">p</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> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex gap-2 "</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>Size:<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-center text-white min-w-14"</span>&gt;</span>{dog.size}<span class="hljs-tag">&lt;/<span class="hljs-name">p</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> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex gap-2 "</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>Color:<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-center text-white capitalize min-w-14"</span>&gt;</span>
                    {dog.color}
                  <span class="hljs-tag">&lt;/<span class="hljs-name">p</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> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex gap-2 "</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>Age:<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-center text-white min-w-14"</span>&gt;</span>
                    {`${dog.age + " " + "year"}${dog.age &gt; 1 ? "s" : ""}`}
                  <span class="hljs-tag">&lt;/<span class="hljs-name">p</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 class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
          ))}

          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"absolute bottom-0 left-0 p-1 translate-y-[110%]"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mb-2"</span>&gt;</span>Filter by<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex items-center mb-4"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">h3</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"w-12"</span>&gt;</span>Size:<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex gap-2"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
                  // <span class="hljs-attr">Reset</span> <span class="hljs-attr">size</span> <span class="hljs-attr">state</span>
                  <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> setSizeFilter(null)}
                  className={`p-2 text-center bg-white rounded-md min-w-14 `}&gt;
                  All
                <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
                  // <span class="hljs-attr">Set</span> <span class="hljs-attr">filter</span> <span class="hljs-attr">to</span> <span class="hljs-attr">small</span>
                  <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> setSizeFilter("S")}
                  className={`p-2 text-center bg-white rounded-md min-w-14 `}&gt;
                  S
                <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
                  // <span class="hljs-attr">Set</span> <span class="hljs-attr">filter</span> <span class="hljs-attr">to</span> <span class="hljs-attr">medium</span>
                  <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> setSizeFilter("M")}
                  className={`p-2 text-center bg-white rounded-md min-w-14 `}&gt;
                  M
                <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
                  // <span class="hljs-attr">Set</span> <span class="hljs-attr">filter</span> <span class="hljs-attr">to</span> <span class="hljs-attr">large</span>
                  <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> setSizeFilter("L")}
                  className={`p-2 text-center bg-white rounded-md min-w-14 `}&gt;
                  L
                <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex items-center"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">h3</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"w-12"</span>&gt;</span>Color:<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex gap-2"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
                  // <span class="hljs-attr">Reset</span> <span class="hljs-attr">color</span> <span class="hljs-attr">state</span>
                  <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> setColorFilter(null)}
                  className={`p-2 text-center bg-white  rounded-md min-w-14 `}&gt;
                  All
                <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
                  // <span class="hljs-attr">Set</span> <span class="hljs-attr">color</span> <span class="hljs-attr">to</span> <span class="hljs-attr">white</span>
                  <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> setColorFilter("white")}
                  className={`p-2 text-center bg-white  rounded-md min-w-14 `}&gt;
                  White
                <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
                  // <span class="hljs-attr">Set</span> <span class="hljs-attr">color</span> <span class="hljs-attr">to</span> <span class="hljs-attr">brown</span>
                  <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> setColorFilter("brown")}
                  className={`p-2 text-center rounded-md bg-white min-w-14 `}&gt;
                  Brown
                <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>

                <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
                  // <span class="hljs-attr">Set</span> <span class="hljs-attr">color</span> <span class="hljs-attr">to</span> <span class="hljs-attr">black</span>
                  <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> setColorFilter("black")}
                  className={`p-2 text-center rounded-md bg-white  min-w-14 `}&gt;
                  Black
                <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</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>
      &lt;/main&gt;
</code></pre>
<p>Testing your component now gives the following result:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/03/Filtering-by-properties.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Filtering by properties working</em></p>
<p>Exquisite!🍦</p>
<p>To add our breadcrumb functionality, pass in the filter props to the component like this:</p>
<pre><code class="lang-jsx">&lt;Breadcrumb sizeFilter={sizeFilter} colorFilter={colorFilter} /&gt;
</code></pre>
<p>Then use those props to render the headers:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> RightArrowImg <span class="hljs-keyword">from</span> <span class="hljs-string">"./assets/right-icon.png"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Breadcrumb</span>(<span class="hljs-params">{ sizeFilter, colorFilter }</span>) </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">"mb-4 bg-gray-200 rounded-md "</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"   flex items-center  text-xl text-[#2E4053] text-left"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">cursor-pointer</span> <span class="hljs-attr">p-4</span> <span class="hljs-attr">rounded-md</span> `}&gt;</span>All<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>

        {sizeFilter &amp;&amp; (
          <span class="hljs-tag">&lt;&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{RightArrowImg}</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"w-5 h-5 "</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</span> /&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">cursor-pointer</span> <span class="hljs-attr">p-4</span> <span class="hljs-attr">rounded-md</span> <span class="hljs-attr">capitalize</span>`}&gt;</span>
              {sizeFilter}
            <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
          <span class="hljs-tag">&lt;/&gt;</span>
        )}
        {colorFilter &amp;&amp; (
          <span class="hljs-tag">&lt;&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{RightArrowImg}</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"w-5 h-5 "</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</span> /&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">cursor-pointer</span> <span class="hljs-attr">p-4</span> <span class="hljs-attr">rounded-md</span> <span class="hljs-attr">capitalize</span>`}&gt;</span>
              {colorFilter}
            <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
          <span class="hljs-tag">&lt;/&gt;</span></span>
        )}
      &lt;/ul&gt;
    &lt;/div&gt;
  );
}
</code></pre>
<p>Before we see the final result, let’s add indicators of what filter props are currently active:</p>
<pre><code class="lang-jsx">&lt;main&gt;
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"relative grid grid-cols-5 gap-6"</span>&gt;</span>
          {filteredDogs.map((dog) =&gt; (
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{dog.name}</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">" w-[225px] rounded-md overflow-hidden"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"w-full "</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{dog.image}</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</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> <span class="hljs-attr">className</span>=<span class="hljs-string">"grid items-center grid-cols-2 gap-2 mt-2"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex items-center gap-2"</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>Name:<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-center text-white bg-orange-900 border rounded-[4px] p-1.5 min-w-14"</span>&gt;</span>
                    {dog.name}
                  <span class="hljs-tag">&lt;/<span class="hljs-name">p</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> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex gap-2 "</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>Size:<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-center text-white min-w-14"</span>&gt;</span>{dog.size}<span class="hljs-tag">&lt;/<span class="hljs-name">p</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> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex gap-2 "</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>Color:<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-center text-white capitalize min-w-14"</span>&gt;</span>
                    {dog.color}
                  <span class="hljs-tag">&lt;/<span class="hljs-name">p</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> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex gap-2 "</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>Age:<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-center text-white min-w-14"</span>&gt;</span>
                    {`${dog.age + " " + "year"}${dog.age &gt; 1 ? "s" : ""}`}
                  <span class="hljs-tag">&lt;/<span class="hljs-name">p</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 class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
          ))}

          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"absolute bottom-0 left-0 p-1 translate-y-[110%]"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mb-2"</span>&gt;</span>Filter by<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex items-center mb-4"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">h3</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"w-12"</span>&gt;</span>Size:<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex gap-2"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
                  <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> setSizeFilter(null)}
                  className={`p-2 text-center  rounded-md min-w-14 ${
                    // Dynamic background color add
                    sizeFilter === null
                      ? "bg-orange-900 text-white"
                      : "bg-white text-black "
                  }`}&gt;
                  All
                <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
                  <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> setSizeFilter("S")}
                  className={`p-2 text-center  rounded-md min-w-14 ${
                    // Dynamic background color add
                    sizeFilter === "S"
                      ? "bg-orange-900 text-white"
                      : "bg-white text-black "
                  }`}&gt;
                  S
                <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
                  <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> setSizeFilter("M")}
                  className={`p-2 text-center  rounded-md min-w-14 ${
                    // Dynamic background color add
                    sizeFilter === "M"
                      ? "bg-orange-900 text-white"
                      : "bg-white text-black "
                  }`}&gt;
                  M
                <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
                  <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> setSizeFilter("L")}
                  className={`p-2 text-center  rounded-md min-w-14 ${
                    // Dynamic background color add
                    sizeFilter === "L"
                      ? "bg-orange-900 text-white"
                      : "bg-white text-black "
                  }`}&gt;
                  L
                <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex items-center"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">h3</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"w-12"</span>&gt;</span>Color:<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex gap-2"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
                  <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> setColorFilter(null)}
                  className={`p-2 text-center   rounded-md min-w-14 ${
                    // Dynamic background color add
                    colorFilter === null
                      ? "bg-orange-900 text-white"
                      : "bg-white text-black "
                  }`}&gt;
                  All
                <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
                  <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> setColorFilter("white")}
                  className={`p-2 text-center   rounded-md min-w-14 ${
                    // Dynamic background color add
                    colorFilter === "white"
                      ? "bg-orange-900 text-white"
                      : "bg-white text-black "
                  }`}&gt;
                  White
                <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
                  <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> setColorFilter("brown")}
                  className={`p-2 text-center rounded-md   min-w-14 ${
                    // Dynamic background color add
                    colorFilter === "brown"
                      ? "bg-orange-900 text-white"
                      : " bg-white text-black "
                  }`}&gt;
                  Brown
                <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>

                <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
                  <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> setColorFilter("black")}
                  className={`p-2 text-center rounded-md    min-w-14 ${
                    // Dynamic background color add
                    colorFilter === "black"
                      ? "bg-orange-900 text-white"
                      : " bg-white text-black"
                  }`}&gt;
                  Black
                <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</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>
      &lt;/main&gt;
</code></pre>
<p>A final test on your component now gives this result:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/03/Filtering-by-properties-tested.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Filtering via properties and showing it in the breadcrumb</em></p>
<p>And voilà! Your component filters perfectly, and also shows a useful breadcrumb to help users know what properties they’ve filtered by.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/03/bruce-almighty-jim-carrey.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Bruce Almighty Jim Carrey beautiful gif</em></p>
<h2 id="heading-best-practices-for-breadcrumbs-in-react">Best Practices for Breadcrumbs in React</h2>
<p>When implementing breadcrumbs in React, it's crucial to follow certain best practices to ensure a seamless user experience. Here are some key points to consider:</p>
<ol>
<li><strong>Consistency with React Routing</strong>: Breadcrumbs should align with the application's routing structure. You can do this by implementing dynamic breadcrumbs using a good routing library (React Router). By defining routes and generating an array of breadcrumbs based on the user's current route, you can ensure that the breadcrumb trail reflects the user's navigation path.</li>
<li><strong>Breadth and Depth of Breadcrumb Trails</strong>: Breadcrumb trails should represent the user's location within the application. This includes using a separator, such as a slash ("/"), to distinguish between different parts of the breadcrumb trail.</li>
<li><strong>Naming and Navigation</strong>: Breadcrumbs should be easy to understand and navigate. This involves using clear and descriptive names for each breadcrumb and ensuring that each breadcrumb link is clickable, leading the user to the appropriate page.</li>
<li><strong>Ensuring Accessibility</strong>: Breadcrumbs should be accessible to all users. This can be achieved by using the <code>aria-label</code> attribute to identify the breadcrumb trail as a navigation landmark. This makes it easier for users with assistive technologies to locate and navigate the breadcrumb trail.</li>
<li><strong>Customization and Ease-of-Use</strong>: When using a component for creating breadcrumbs, consider its customization options and ease of use. Look for components that provide useful defaults and allow for easy customization of texts, links, and separators.</li>
</ol>
<p>By adhering to these best practices, you can create effective and user-friendly breadcrumbs in your React applications. </p>
<p>Here are links to the repositories on GitHub:</p>
<ul>
<li><a target="_blank" href="https://github.com/Daiveedjay/React-breadcrumb-article-location-based">Location-based</a></li>
<li><a target="_blank" href="https://github.com/Daiveedjay/React-breadcrumb-article-path-based">Path-based</a></li>
<li><a target="_blank" href="https://github.com/Daiveedjay/React-breadcrumb-article-attribute-based">Attribute-based</a></li>
</ul>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Implementing breadcrumbs in React applications not only provides a navigational aid but also contributes to a seamless and intuitive user experience. Adhering to best practices enhances the usability and accessibility of applications.</p>
<p>Just as the aroma of freshly baked bread entices hungry people to come visit the bakery, a well-structured breadcrumb trail can entice users to explore and navigate an application with ease, ultimately improving user navigation and experience. And that's how the cookie crumbles, leaving a trail of delightful navigation in its wake.</p>
<h3 id="heading-contact-information">Contact Information</h3>
<p>Want to connect or contact me? Feel free to hit me up on the following:</p>
<ul>
<li>Twitter / X: <a target="_blank" href="https://twitter.com/JajaDavid8">@jajadavid8</a></li>
<li>LinkedIn: <a target="_blank" href="https://www.linkedin.com/in/david-jaja-8084251b4/">David Jaja</a></li>
<li>Email: Jajadavidjid@gmail.com  </li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Learn the Hard Parts of React – and Tips to Conquer Them ]]>
                </title>
                <description>
                    <![CDATA[ Have you started learning React, only to face bugs that made you contemplate a career in goat herding? Don't worry – we've all been there.  In this guide, you'll join me on a quest through the quirky wonders of React. I'll help you navigate the perpl... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/hard-parts-of-react/</link>
                <guid isPermaLink="false">66bb8901bec1b237336e966f</guid>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ David Jaja ]]>
                </dc:creator>
                <pubDate>Mon, 26 Feb 2024 21:07:53 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/02/Article-Cover.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Have you started learning React, only to face bugs that made you contemplate a career in goat herding? Don't worry – we've all been there. </p>
<p>In this guide, you'll join me on a quest through the quirky wonders of React. I'll help you navigate the perplexing moments, ensuring you never have to ask yourself, "What’s up with React?"</p>
<p>Whether you're a seasoned React adventurer or unearthing the mysteries of virtual DOMs, fear not. I'm here to share the tales of my early struggles, demystify the enigmatic bugs, and pave the way for a smoother journey.</p>
<h3 id="heading-prerequisites">Prerequisites</h3>
<ul>
<li>Fundamentals of HTML and CSS</li>
<li>Fundamentals of ES6 JavaScript and React</li>
</ul>
<h2 id="heading-what-well-cover"><strong>What We'll Cover:</strong></h2>
<ol>
<li><a class="post-section-overview" href="#heading-what-well-cover">Quick Recap of React Fundamentals</a><br>– <a class="post-section-overview" href="#heading-components-the-web-building-blocks">Components: The Web Building Blocks</a><br>– <a class="post-section-overview" href="#heading-jsx-where-html-meets-javascript">JSX: Where HTML Meets JavaScript</a><br>– <a class="post-section-overview" href="#heading-state-and-props-the-dynamic-duo">State and Props: The Dynamic Duo</a></li>
<li><a class="post-section-overview" href="#the-good-the-bad-and-the-challenging-parts-of-react">The Good, the Bad, and the Challenging Parts of React</a><br>– <a class="post-section-overview" href="#heading-the-good-parts-of-react">The Good Parts of React</a><br>– <a class="post-section-overview" href="#heading-the-bad-parts-of-react">The Bad Parts of React</a><br>– <a class="post-section-overview" href="#heading-the-challenging-parts-of-react">The Challenging Parts of React</a><br>     – <a class="post-section-overview" href="#heading-key-prop-mishaps">Key Prop Mishaps</a><br>     – <a class="post-section-overview" href="#heading-mutating-states-directly">Mutating States Directly</a><br>     – <a class="post-section-overview" href="#heading-mysterious-bugs-with-conditional-rendering">Mysterious Bugs with Conditional Rendering</a><br>     – <a class="post-section-overview" href="#heading-ignoring-dependency-arrays-in-react-hooks">Ignoring Dependency Arrays in React Hooks</a><br>     – <a class="post-section-overview" href="#heading-neglecting-optional-chaining-for-api-data">Neglecting Optional Chaining for API Data</a><br>     – <a class="post-section-overview" href="#heading-ignoring-react-fragments-for-grouping-jsx-elements">Ignoring React Fragments for Grouping JSX Elements</a></li>
<li><a class="post-section-overview" href="#heading-opinionated-approaches-to-react">Opinionated Approaches to React</a></li>
<li><a class="post-section-overview" href="#heading-wrapping-up-the-quirky-journey-with-react">Wrapping Up the Quirky Journey with React</a></li>
</ol>
<h2 id="heading-quick-recap-of-react-fundamentals">Quick Recap of React Fundamentals</h2>
<p>The React library revolves around 3 building blocks: Components, JSX, and State &amp; Props.</p>
<h3 id="heading-components-the-web-building-blocks">Components: The Web Building Blocks</h3>
<p>Imagine components as the LEGO bricks of your user interface—a single, reusable piece that contributes to the grand structure. They encapsulate functionality, styling, and behavior, making your UI both modular and scalable. </p>
<p>From a simple button to an elaborate sidebar, components are the heart and soul of React development.</p>
<h3 id="heading-jsx-where-html-meets-javascript">JSX: Where HTML Meets JavaScript</h3>
<p>JSX, or JavaScript XML, may seem like an odd fusion of HTML and JavaScript at first, but it’s quite straightforward. It's the secret sauce that makes React's syntax so expressive and dynamic. </p>
<p>With JSX, you write your UI components using a syntax that resembles HTML, but underneath, it's pure JavaScript.</p>
<h3 id="heading-state-and-props-the-dynamic-duo">State and Props: The Dynamic Duo</h3>
<p>The dynamic duo of state and props bring React pages to life as they add interactivity to your web applications.</p>
<h4 id="heading-state-granting-memory-to-components">State: Granting Memory to Components</h4>
<p>State provides memory to components, allowing them to remember past events and alter their behavior over time. It's the key to making your UI responsive and dynamic. </p>
<p>Picture a form that remembers the user's input or a counter that increments with each click. That's the magic of state.</p>
<h4 id="heading-props-enabling-communication">Props: Enabling Communication</h4>
<p>Props (short for properties) facilitate communication between components. They allow parent components to pass data down to their children, creating a seamless flow of information. </p>
<p>Think of props as messengers, ensuring that each component knows its role and receives the necessary information to perform it.</p>
<h2 id="heading-the-good-the-bad-and-the-puzzling-parts-of-react">The Good, the Bad, and the Puzzling Parts of React</h2>
<p>Before we delve into the puzzling aspects of React, it's essential to shine a spotlight on the treasures that make React a true hero in your arsenal.</p>
<h3 id="heading-the-good-parts-of-react">The Good Parts of React</h3>
<h4 id="heading-virtual-dom-and-its-advantages">Virtual DOM and its Advantages</h4>
<p>The virtual DOM is a revolutionary concept that gives React its speed and efficiency. </p>
<p>When changes occur in your app, React doesn't immediately update the actual DOM. Instead, it works with a lightweight copy, the Virtual DOM, making minimal, lightning-fast adjustments. This not only optimizes performance but also provides a smoother user experience.</p>
<pre><code class="lang-js">ReactDOM.createRoot(<span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"root"</span>)).render(
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">App</span> /&gt;</span></span>
 );
</code></pre>
<p>This process leverages <a target="_blank" href="https://legacy.reactjs.org/docs/reconciliation.html">React's diffing algorithm</a> in the Virtual DOM. It identifies the minimal set of changes needed in the actual DOM to reflect the updated state.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/00--Explaing-how-react-updates-the-UI-using-the-virtual-DOM.png" alt="Image" width="600" height="400" loading="lazy">
<em>Explaining how React updates the UI using the virtual DOM</em></p>
<h4 id="heading-reusable-components">Reusable Components</h4>
<p>In React, the guiding principle is reusability. Components, the fundamental building blocks we discussed above, can be crafted and employed across your application. This not only fosters a modular and organized code structure but also frees you from the burden of reinventing the wheel.</p>
<pre><code class="lang-js"><span class="hljs-comment">// Reusable Button Component</span>
<span class="hljs-keyword">const</span> Button = <span class="hljs-function">(<span class="hljs-params">{ label, onClick }</span>) =&gt;</span> (
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{onClick}</span>&gt;</span>{label}<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></span>
);

<span class="hljs-comment">// Usage</span>
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Button</span> <span class="hljs-attr">label</span>=<span class="hljs-string">"Click me"</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> console.log("Button Clicked")} /&gt;</span>
</code></pre>
<h4 id="heading-one-way-data-binding-for-a-predictable-flow">One-way Data Binding for a Predictable Flow</h4>
<p>React enforces a unidirectional data flow, ensuring predictability and maintainability. </p>
<p>Parent components convey data down to their children through props, and any modifications are overseen by the parent component. This one-way street prevents the chaos with 2-way data binding seen in other frameworks.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> ParentComponent = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> [data, setData] = useState(<span class="hljs-string">"Hello from Parent!"</span>);

  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ChildComponent</span> <span class="hljs-attr">data</span>=<span class="hljs-string">{data}</span> /&gt;</span></span>;
};

<span class="hljs-keyword">const</span> ChildComponent = <span class="hljs-function">(<span class="hljs-params">{ data }</span>) =&gt;</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>{data}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>;
</code></pre>
<h3 id="heading-the-bad-parts-of-react">The Bad Parts of React</h3>
<p>There are some parts of React that aren't ideal, though. Let's go through them briefly now so you can be aware of them.</p>
<h4 id="heading-steep-learning-curve-for-beginners">Steep Learning Curve for Beginners</h4>
<p>Starting with React can be tough, especially if you're new to web development. Concepts like JSX, components, and state management might seem like a maze. But don't worry! With some practice and patience, it gets easier, and React becomes more familiar.</p>
<h4 id="heading-jsx-might-puzzle-you-at-first">JSX Might Puzzle You at First</h4>
<p>JSX, the special mix of HTML and JavaScript, can be a bit confusing at the beginning. It's like learning a new language that blends the two. But as you get the hang of it, you'll see how it makes your code shorter and clearer.</p>
<h4 id="heading-state-management-challenges">State Management Challenges</h4>
<p>Using state in React is powerful, but it can also be tricky. Handling state across lots of different pieces, especially in big projects, can create complex setups and potential problems. Luckily, tools like <a target="_blank" href="https://redux.js.org/">Redux</a> exist to help manage this complexity.</p>
<h2 id="heading-the-challenging-parts-of-react">The Challenging Parts of React</h2>
<h3 id="heading-key-prop-mishaps">Key Prop Mishaps</h3>
<p>When building your applications, you may often have repeating elements which show similar information or share the same styles. The logical step would be to loop over them to create a list of elements.</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ListComponent</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> people = [{ <span class="hljs-attr">name</span>: <span class="hljs-string">"Mitchelle"</span> }, { <span class="hljs-attr">name</span>: <span class="hljs-string">"July"</span> }, { <span class="hljs-attr">name</span>: <span class="hljs-string">"David"</span> }];
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
      {/ Looping over the people array to create list items /}
      {people.map((person) =&gt; (
        <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>{person.name}<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>
  );
}
</code></pre>
<p>Everything seems fine until you notice a warning in your console or, worse, strange behaviour in how your list renders.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/02--The-console-an-error-due-to-missing-key-prop.png" alt="Image" width="600" height="400" loading="lazy">
<em>The console an error due to missing key prop</em></p>
<p>React uses keys to update and reorder elements in a list. When you forget to provide a key prop or if the keys are not unique, React gets a bit lost. It's like trying to keep track of items in the array without any specific identifiers – things get mixed up, and you might end up with unexpected bugs in your UI.</p>
<h4 id="heading-how-to-solve-it">How to solve it</h4>
<p>The first instinct for many developers when faced with creating dynamic lists is to use the index property as the key. It seems like a convenient solution, as the index provides a unique identifier for each element in the array – but it isn’t the best approach for the following reasons:</p>
<ul>
<li><strong>Non-Persistent</strong>: If the order or number of items changes, React may get confused. For example, if an item is added or removed from the beginning of the list, all the subsequent indices change, causing potential re-rendering issues.</li>
<li><strong>Array Mutations</strong>: Operations like sorting or filtering can alter the order of items, breaking the association between the index and the actual item.</li>
<li><strong>Performance Concerns</strong>: React relies on keys for efficient updates. Using the index as a key might impact performance when dealing with large lists or frequent updates.</li>
</ul>
<p>Some of the better alternatives include:</p>
<ul>
<li><strong>Use a Unique ID</strong>: If each item in your array has a unique identifier, such as an <code>id</code> property, use that as the key.</li>
</ul>
<pre><code class="lang-js">{people.map(<span class="hljs-function">(<span class="hljs-params">person</span>) =&gt;</span> (
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{person.id}</span>&gt;</span>{person.name}<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span></span>
))}
</code></pre>
<ul>
<li>Generate a Unique Key: In cases where items lack a natural unique identifier, consider using a function like <code>crypto.randomUUID()</code> to generate a unique key.</li>
</ul>
<pre><code class="lang-js">
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ListComponent</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> people = [
    { <span class="hljs-attr">name</span>: <span class="hljs-string">"Mitchelle"</span>, <span class="hljs-attr">age</span>: <span class="hljs-number">25</span>, <span class="hljs-attr">occupation</span>: <span class="hljs-string">"Engineer"</span> },
    { <span class="hljs-attr">name</span>: <span class="hljs-string">"July"</span>, <span class="hljs-attr">age</span>: <span class="hljs-number">30</span>, <span class="hljs-attr">occupation</span>: <span class="hljs-string">"Doctor"</span> },
    { <span class="hljs-attr">name</span>: <span class="hljs-string">"David"</span>, <span class="hljs-attr">age</span>: <span class="hljs-number">35</span>, <span class="hljs-attr">occupation</span>: <span class="hljs-string">"Artist"</span> }
  ];

  <span class="hljs-comment">// Generate unique IDs for each person before rendering</span>
  <span class="hljs-keyword">const</span> peopleWithIds = people.map(<span class="hljs-function"><span class="hljs-params">person</span> =&gt;</span> ({
    ...person,
    <span class="hljs-attr">id</span>: crypto.randomUUID(),
  }));

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
      {/* Looping over the people array to create list items */}
      {peopleWithIds.map((person) =&gt; (
        <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{person.id}</span>&gt;</span>{person.name}<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>
  );
}
</code></pre>
<p>By choosing one of these alternatives, you provide React with stable and unique keys, helping it manage and update your dynamic lists,</p>
<p><strong>Note</strong>: You may be thinking “If <code>crypto.randomUUID</code> generates a unique ID, (<code>Math.random()</code> * some big number) would work the same, right”?</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/Nope.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Nope gif</em></p>
<p><code>Math.random()</code> could also suffice as a key, but it's a bad idea because the generated keys won't be stable across re-renders, leading to potential performance issues and rendering inconsistencies.</p>
<h3 id="heading-mutating-states-directly">Mutating States Directly</h3>
<p>Imagine you're working on a component that manages an array of names. Rather than using the appropriate setter method to update the state, you decide to directly mutate the state.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> MutableStateComponent = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> [names, setNames] = useState([<span class="hljs-string">"David"</span>, <span class="hljs-string">"John"</span>, <span class="hljs-string">"Steph"</span>, <span class="hljs-string">"Anthony"</span>]);

  <span class="hljs-keyword">const</span> removeLastName = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-built_in">console</span>.log(names);
    <span class="hljs-comment">// Direct mutation of state using pop()</span>
    names.pop();
    setNames(names); <span class="hljs-comment">// This won't trigger a re-render</span>
  };

  <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">p</span>&gt;</span>Names: {names.join(", ")}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{removeLastName}</span>&gt;</span>Remove Last Name<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>
  );
};
</code></pre>
<p>To your surprise, the UI doesn't update as expected, and you find yourself stuck in a scenario where the list of names seems frozen. Make no mistake, the array is getting updated as seen below:</p>
<p><img src="https://lh7-us.googleusercontent.com/yey1I5L7W43d8vcNl7kEUZaRHGZw90xZfviK3rhfFHiqwXv3gsCjHqcs9nhgdWoQlbPEGAj2A_7qHcoeRI9xPtsD0JCiPJdzT4MNRrQ91GfUjdwvW4hmlHGE_LtdG49FzO1buO0yT9tzMRtO95MgvYI" alt="Image" width="600" height="185" loading="lazy">
<em>Array getting mutated with UI being updated</em></p>
<h4 id="heading-whats-the-problem">What's the Problem?</h4>
<p>React relies on an immutable state for efficient updates, and when you bypass this mechanism, it disrupts the unidirectional data flow. </p>
<p>In this case, using <code>pop()</code> mutates the original array in place, and React loses track of the changes. This leads to an inaccurate rendering of the component.</p>
<h4 id="heading-how-to-solve-it-1">How to Solve it</h4>
<p>To ensure your component behaves as expected and follows React's principles, always use the setter function (<code>setNames</code>) to update the state.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> MutableStateComponent = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> [names, setNames] = useState([<span class="hljs-string">"David"</span>, <span class="hljs-string">"John"</span>, <span class="hljs-string">"Steph"</span>, <span class="hljs-string">"Anthony"</span>]);

  <span class="hljs-keyword">const</span> removeLastName = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-comment">// Use setNames to update state</span>
    setNames(<span class="hljs-function">(<span class="hljs-params">prevNames</span>) =&gt;</span> prevNames.slice(<span class="hljs-number">0</span>, <span class="hljs-number">-1</span>));
    <span class="hljs-built_in">console</span>.log(names);
  };

  <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">p</span>&gt;</span>Names: {names.join(", ")}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{removeLastName}</span>&gt;</span>Remove Last Name<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>
  );
};
</code></pre>
<p>By using <code>setNames</code> and creating a new array with the desired changes (in this case, using <code>slice</code> to remove the last element), you ensure that React can accurately track and update the state, resulting in the expected UI behavior.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/09--Result-of-Mutating-States-with-the-correct-method.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Result of mutating states with the correct method</em></p>
<h3 id="heading-mysterious-bugs-with-conditional-rendering">Mysterious Bugs with Conditional Rendering</h3>
<p>Conditional rendering, while powerful, can introduce subtle bugs when not handled with care. Understanding common pitfalls, particularly those related to truthy and falsy evaluations, is crucial for preventing mysterious rendering behaviour.</p>
<p>Consider the following example:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> IncorrectConditionalComponent = <span class="hljs-function">(<span class="hljs-params">{ showContent }</span>) =&gt;</span> (
  {showContent &amp;&amp; <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>Show me if true!<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>}
);
</code></pre>
<h4 id="heading-the-bug-unexpected-rendering-with-falsy-values">The Bug: Unexpected Rendering with Falsy Values</h4>
<p>In this code snippet, if <code>showContent</code> happens to be a falsy value, such as <code>0</code>, the component will render an unexpected result. Instead of gracefully not rendering the content, it will display <code>0</code> on the screen due to the direct inclusion of curly braces.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/Gotcha.gif" alt="Image" width="600" height="400" loading="lazy">
<em>I gotcha gif</em></p>
<h4 id="heading-whats-the-problem-1">What's the Problem?</h4>
<p>The issue lies in the mismanagement of truthy and falsy values. The direct use of curly braces creates an object wrapper (<code>[object Object]</code>), causing the component to render whatever value is present, even if it's falsy.</p>
<h4 id="heading-how-to-solve-it-2">How to Solve it</h4>
<p>To catch rendering bugs related to truthy and falsy values, use a more explicit conditional check.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> CorrectConditionalComponent = <span class="hljs-function">(<span class="hljs-params">{ showContent }</span>) =&gt;</span> (
  showContent ? <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>Show me if true!<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span> : <span class="hljs-literal">null</span>
);
</code></pre>
<p>In this corrected version, the ternary operator ensures a clear check for truthiness, preventing unexpected rendering issues. By explicitly handling truthy and falsy values, you build robust components that behave predictably in various scenarios.</p>
<h3 id="heading-ignoring-dependency-arrays-in-react-hooks">Ignoring Dependency Arrays in React Hooks</h3>
<p>Imagine working on a component that relies on an effect to perform some logic when a certain state, let's say <code>count</code>, changes. But even though you're incrementing the count, the effect doesn't seem to run, and you're left wondering why your logic isn't taking effect.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> Counter = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> [count, setCount] = useState(<span class="hljs-number">0</span>);

  <span class="hljs-keyword">const</span> handleClick = <span class="hljs-function">() =&gt;</span> {

    setCount(<span class="hljs-function">(<span class="hljs-params">count</span>) =&gt;</span> count + <span class="hljs-number">1</span>);
  };

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"The current count value is "</span>, count);
  }, []);

  <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">p</span>&gt;</span>Count: {count}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handleClick}</span>&gt;</span>Increment<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>
  );
};
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/03--testing-the-count-component-without-fixing-the-useEffect-dependency-array.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Testing the count component without fixing the useEffect dependency array</em></p>
<h4 id="heading-whats-the-problem-2">What's the Problem?</h4>
<p>The issue lies in neglecting the dependency array in your <code>useEffect</code>. When you omit the dependencies, React might not recognize that the effect is tied to a specific piece of state, leading to stale data and unexpected behavior.</p>
<h4 id="heading-how-to-solve-it-3">How to Solve it</h4>
<p>To get your effect back on track, include the relevant dependencies in the dependency array. It's like setting up triggers – you're telling React, "Hey, run this effect whenever these specific pieces of data change."</p>
<pre><code class="lang-js">useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"The current count value is "</span>, count);
  }, [count]);
</code></pre>
<p>Which now fires the <code>useEffect</code> hook:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/04--testing-the-count-component-after-fixing-the-useEffect-dependency-array.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Testing the count component after fixing the useEffect dependency array</em></p>
<h3 id="heading-neglecting-optional-chaining-for-api-data">Neglecting Optional Chaining for API Data</h3>
<p>You're working on a component that displays user data fetched from an API. Everything seems fine until you encounter an unexpected runtime error. The culprit? A missing optional chaining operator.</p>
<h4 id="heading-whats-the-problem-3">What's the Problem?</h4>
<p>API responses can be unpredictable, and not all data structures match your expectations. Neglecting optional chaining, especially when accessing deeply nested properties (looking at you Strapi response data 👀) can lead to runtime errors if a property is undefined.</p>
<h4 id="heading-how-to-solve-it-4">How to Solve it</h4>
<p>To safeguard your component from unexpected errors, incorporate optional chaining (<code>?.</code>) when accessing nested properties in API data.</p>
<p>As an example, say you want to read a deeply nested property (label) from this data:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> data = {
    <span class="hljs-attr">id</span>: <span class="hljs-number">1</span>,
    <span class="hljs-attr">title</span>: <span class="hljs-string">"First Item"</span>,
    <span class="hljs-attr">content</span>: <span class="hljs-string">"Content for the first item"</span>,
    <span class="hljs-attr">category</span>: {
      <span class="hljs-attr">id</span>: <span class="hljs-number">101</span>,
      <span class="hljs-attr">name</span>: <span class="hljs-string">"Category A"</span>,
      <span class="hljs-attr">description</span>: <span class="hljs-string">"Description of Category A"</span>,
      <span class="hljs-attr">tags</span>: [
        {
          <span class="hljs-attr">id</span>: <span class="hljs-number">1001</span>,
          <span class="hljs-attr">label</span>: <span class="hljs-string">"Tag 1"</span>,
        },
        {
          <span class="hljs-attr">id</span>: <span class="hljs-number">1002</span>,
          <span class="hljs-attr">label</span>: <span class="hljs-string">"Tag 2"</span>,
        },
      ],
    },
    <span class="hljs-attr">author</span>: {
      <span class="hljs-attr">id</span>: <span class="hljs-number">201</span>,
      <span class="hljs-attr">name</span>: <span class="hljs-string">"John Doe"</span>,
      <span class="hljs-attr">email</span>: <span class="hljs-string">"john.doe@example.com"</span>,
    },
  };
</code></pre>
<p>The correct way would be to use optional chaining to retrieve that data:</p>
<pre><code class="lang-js"> <span class="hljs-keyword">const</span> firstLabel = data?.category?.tags?.[<span class="hljs-number">0</span>]?.label;
</code></pre>
<p>Rather than accessing those properties directly:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> firstLabel = data.category.tags[<span class="hljs-number">0</span>].label;
</code></pre>
<p>This prevents you from seeing a white screen error and a flooded console if the data structure changes. It's like putting on a safety net – if a property is missing, your app won't come crashing down like so:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/05--Error-occuring-when-optional-chaining-isn-t-applied.png" alt="Image" width="600" height="400" loading="lazy">
<em>Error occurring when optional chaining isn't applied</em></p>
<h3 id="heading-ignoring-react-fragments-for-grouping-jsx-elements">Ignoring React Fragments for Grouping JSX Elements</h3>
<p>When working with React components, you may encounter a scenario where you want to return multiple JSX elements from a function, only to be met with a syntax error.</p>
<h4 id="heading-whats-the-problem-4">What's the Problem?</h4>
<p>This is due to a limitation in JavaScript, as it doesn't allow the return of adjacent elements without a common parent.</p>
<p>Consider the following problematic code:</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">User</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">div</span>&gt;</span> David Jaja<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
         <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>Twitter: https://twitter.com/JajaDavid8<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>;
}
</code></pre>
<p>This code results in an error: “Adjacent JSX elements must be wrapped in an enclosing tag.”</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/06--Error-occuring-when-JSX-returns-2-direct-adjacent-elements.png" alt="Image" width="600" height="400" loading="lazy">
<em>Error occurring when JSX returns 2 direct adjacent elements</em></p>
<h4 id="heading-how-to-solve-it-5">How to Solve it</h4>
<p>I know what you might be thinking—why not simply wrap the elements in a div and move on?</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/sponge-bob-bored.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Spongebob bored gif</em></p>
<p>While this seems like a quick fix, it introduces a potential downside. By adding a div, you create an unnecessary parent element in the DOM. </p>
<p>This additional markup, though resolving the immediate error, can lead to unintended consequences, such as affecting styles or layout, and may not align with optimal coding practices. </p>
<p>And I’m sure you don’t want to end up with a "divpocalipse". </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/07--Divpocalpse.png" alt="Image" width="600" height="400" loading="lazy">
<em>A divpocalpse</em></p>
<p>To overcome both the syntax error and the unnecessary DOM markup, React introduced an optimized solution: React Fragments.</p>
<p>React Fragments are used to address the need for returning multiple JSX elements without introducing unnecessary parent elements in the DOM.</p>
<p>Here's how you can utilize React Fragments:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">User</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">React.Fragment</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span> David Jaja<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>Twitter: https://twitter.com/JajaDavid8<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">React.Fragment</span>&gt;</span></span>
  );
}
</code></pre>
<p>Or using the shorthand syntax:</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">User</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span> David Jaja<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>Twitter: https://twitter.com/JajaDavid8<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/&gt;</span></span>
  );
}
</code></pre>
<p>By using React Fragments, you maintain clean and concise JSX code without introducing unnecessary elements to the DOM, enhancing code readability.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/Showing-the-DOM-tree-after-using-fragments-without-any-extra-elements.png" alt="Image" width="600" height="400" loading="lazy">
<em>Showing the DOM tree after using fragments without any extra elements</em></p>
<h2 id="heading-opinionated-approaches-to-react">Opinionated Approaches to React</h2>
<p>I've found some handy ways to make working with React more enjoyable. Instead of strict rules, think of these as my personal choices to make code easier to read, improve how it works, and make sure it stays in good shape.</p>
<ol>
<li><strong>Put data outside components</strong>: Move things like lists and groups of information outside the main part of a component when possible. This helps avoid extra updates and makes it simpler to handle data without using special functions like <code>useCallback</code>.</li>
<li><strong>Be careful with <code>React.memo</code></strong>: Using <code>React.memo</code> can help your components run better, but it's not always needed. If a component changes a lot with new information, using <code>React.memo</code> might not be as helpful. Use it wisely.</li>
<li><strong>Create your own custom React hooks</strong>: I also like making my own special tools with custom React hooks. It's a bit advanced, but it helps keep my code neat and organized.</li>
</ol>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/but-thats-just-my-opinion-just-what-i-think.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Just my opinion gif</em></p>
<h2 id="heading-wrapping-up-the-quirky-journey-with-react">Wrapping Up the Quirky Journey with React</h2>
<p>React's journey is a blend of smooth sailing and bumpy rides. We've seen the strength of reusable components and virtual DOM and tackled puzzling moments like missing key props and conditional rendering bugs and so on.</p>
<p>As you continue your journey with React, may your code be clean, your components reusable, and your "What's Up with React?" moments turn into "Aha!" revelations. Happy coding! 🚀</p>
<h3 id="heading-contact-information"><strong>Contact Information</strong></h3>
<p>Want to connect or contact me? Feel free to hit me up on the following:</p>
<ul>
<li>Twitter: <a target="_blank" href="https://twitter.com/JajaDavid8">@jajadavid8</a></li>
<li>LinkedIn: <a target="_blank" href="https://www.linkedin.com/in/david-jaja-8084251b4/">David Jaja</a></li>
<li>Email: Jajadavidjid@gmail.com</li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build a High-Performance Tab Component in React ]]>
                </title>
                <description>
                    <![CDATA[ Tabs are more than mere UI elements – they're the backbone of user navigation and content organization in many applications. In React, crafting a tabbed component that's both efficient and responsive is not just an improvement, it's a necessity. This... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/build-a-high-performance-tab-component/</link>
                <guid isPermaLink="false">66bb88faadd24ba4273250e0</guid>
                
                    <category>
                        <![CDATA[ components ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ David Jaja ]]>
                </dc:creator>
                <pubDate>Thu, 18 Jan 2024 16:01:46 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/07/tabbed-cover-image-new.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Tabs are more than mere UI elements – they're the backbone of user navigation and content organization in many applications. In React, crafting a tabbed component that's both efficient and responsive is not just an improvement, it's a necessity.</p>
<p>This article takes a deep dive into constructing a React tab component that excels in performance and user experience. We'll cover how to create, optimize, and animate tabs effectively.</p>
<p>You'll also learn how to leverage the Profiler in Dev Tools to pinpoint and reduce unnecessary re-renders, and how to apply Framer Motion to elevate your tabs beyond the functional to make them delightful.</p>
<h2 id="heading-prerequisites"><strong>Prerequisites</strong></h2>
<ul>
<li>Fundamentals of HTML and CSS</li>
<li>Fundamentals of ES6 JavaScript</li>
<li>Fundamentals of React and Framer Motion.</li>
</ul>
<h2 id="heading-what-well-cover"><strong>What We'll Cover:</strong></h2>
<ol>
<li><a class="post-section-overview" href="#heading-how-to-set-up-an-environment">How to set up an environment</a></li>
<li><a class="post-section-overview" href="#heading-the-heart-of-the-tab-component">The Heart of the Tab component</a></li>
<li><a class="post-section-overview" href="#heading-how-to-build-the-tab-component">How to build the Tab component</a><br>– <a class="post-section-overview" href="#heading-how-to-build-the-ui">How to build the UI</a><br>– <a class="post-section-overview" href="#heading-how-to-implement-the-tab-functionality">How to implement the Tab functionality</a><br>– <a class="post-section-overview" href="#heading-how-to-optimize-the-tab-component">How to optimize the Tab component</a><br>– <a class="post-section-overview" href="#heading-how-to-animate-the-component">How to animate the component</a></li>
<li><a class="post-section-overview" href="#heading-other-methods-you-can-use-to-fine-tune-for-high-performance">Other methods you can use to fine-tune for high performance</a></li>
<li><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></li>
</ol>
<h2 id="heading-how-to-set-up-an-environment">How to Set Up an Environment</h2>
<p>To build a high-performance React tab component, the first thing to do is set up a clean development environment. </p>
<p>Before you dive into creating React components, make sure to install <a target="_blank" href="https://nodejs.org/en/download">Node.js</a> on your computer. This sets the stage for an efficient development process.</p>
<h2 id="heading-how-to-create-a-react-project">How to Create a React Project</h2>
<p>After installing Node.js, use Vite (a modern build tool for React projects) to create a new React project. In your local terminal, run the command:</p>
<pre><code class="lang-bash">npm create vite@latest
</code></pre>
<p>Select React as your framework and your preferred variant.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/0-React-app-set-up.png" alt="Image" width="600" height="400" loading="lazy">
<em>React app setup</em></p>
<p>Then to install the necessary packages, run <code>npm install</code> and open it in your IDE.</p>
<p>At the moment, your app should look like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/1-React-app-setup.png" alt="Image" width="600" height="400" loading="lazy">
<em>React app setup complete</em></p>
<p>Finally, start up the dev server by running <code>npm run dev</code> and go to the given port.</p>
<h2 id="heading-the-heart-of-the-tab-component">The Heart of the Tab Component</h2>
<p>Imagine the tab component like a smart switchboard, smoothly guiding you through different content sections—similar to flipping TV channels or tuning in to radio stations. </p>
<p>Two main parts make this happen:</p>
<ul>
<li><strong>Tab Buttons</strong>: These act like selector switches, holding individual tabs ready for your clicks. Clicking on these tabs is like choosing different views or content channels.</li>
<li><strong>Tab Panels</strong>: Think of these as the content broadcasts linked to each tab. Only the content connected to the active tab is in the spotlight, just like tuning into a specific channel for clear viewing.</li>
</ul>
<h2 id="heading-how-to-build-the-tab-component">How to Build the Tab Component</h2>
<p>This section includes 4 parts:</p>
<ol>
<li>Building the UI</li>
<li>Implementing the tab functionality</li>
<li>Optimizing the tab component</li>
<li>How to Animate the Component</li>
</ol>
<h3 id="heading-how-to-build-the-ui">How to Build the UI</h3>
<p>This section includes all of the mockups and styling needed to render your component on the page. Here’s a step-by-step walkthrough of the process:</p>
<p>First, create an array containing all the data used by your app in your App component.</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> <span class="hljs-string">"./App.css"</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> petData = [
    {
      <span class="hljs-attr">animal</span>: <span class="hljs-string">"Cheetah"</span>,
      <span class="hljs-attr">fact</span>: <span class="hljs-string">"Cheetahs are the fastest land animals, capable of reaching speeds up to 75 mph."</span>,
      <span class="hljs-attr">image</span>: <span class="hljs-string">"../src/assets/6.svg"</span>,
    },
    {
      <span class="hljs-attr">animal</span>: <span class="hljs-string">"Koala"</span>,
      <span class="hljs-attr">fact</span>: <span class="hljs-string">"Koalas sleep around 20 hours a day and are known for their eucalyptus diet."</span>,
      <span class="hljs-attr">image</span>: <span class="hljs-string">"../src/assets/3.svg"</span>,
    },
    {
      <span class="hljs-attr">animal</span>: <span class="hljs-string">"Elephant"</span>,
      <span class="hljs-attr">fact</span>: <span class="hljs-string">"Elephants have the largest brains among land animals and demonstrate remarkable intelligence."</span>,
      <span class="hljs-attr">image</span>: <span class="hljs-string">"../src/assets/1.svg"</span>,
    },
    {
      <span class="hljs-attr">animal</span>: <span class="hljs-string">"Zebra"</span>,
      <span class="hljs-attr">fact</span>: <span class="hljs-string">"Zebras have distinctive black and white stripes that act as a natural defense against predators."</span>,
      <span class="hljs-attr">image</span>: <span class="hljs-string">"../src/assets/7.svg"</span>,
    },
    {
      <span class="hljs-attr">animal</span>: <span class="hljs-string">"Horse"</span>,
      <span class="hljs-attr">fact</span>: <span class="hljs-string">"Horses have excellent memory and are capable of recognizing human emotions."</span>,
      <span class="hljs-attr">image</span>: <span class="hljs-string">"../src/assets/5.svg"</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">"main__container"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Choose your pet<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>Then create two components <code>TabButtons</code> and <code>TabContent</code> which will control the Tab and display the Tab’s content, respectively. Then import them into the App component.</p>
<p>Next, pass the data array from your app component into both components using props.</p>
<pre><code class="lang-js"><span class="hljs-comment">// Rest of app component</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">"main__container"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Choose your pet<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">TabButtons</span>

        <span class="hljs-attr">petData</span>=<span class="hljs-string">{petData}</span>
      /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">TabContent</span> <span class="hljs-attr">petData</span>=<span class="hljs-string">{petData}</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
</code></pre>
<p>Then loop over the data in both components to create the buttons that'll be used to control the component and the data shown with respect to each tab.</p>
<p>For the <code>TabButtons</code> component:</p>
<pre><code class="lang-js"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">TabButtons</span>(<span class="hljs-params">{ petData }</span>) </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">"tab__header"</span>&gt;</span>
      {petData.map((item, index) =&gt; (
               <span class="hljs-tag">&lt;<span class="hljs-name">li</span>
          <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">tab__button</span>`}
          <span class="hljs-attr">key</span>=<span class="hljs-string">{item.animal}</span>
                 &gt;</span>
          {item.animal}
        <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
      ))}
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<p>The <code>TabContent</code> component:</p>
<pre><code class="lang-js"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">TabContent</span>(<span class="hljs-params">{ petData}</span>) </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">"tab__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">"tab__content"</span>&gt;</span>
        {petData.map((pet) =&gt; (
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{pet}</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{pet.image}</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</span> /&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>{pet.fact}<span class="hljs-tag">&lt;/<span class="hljs-name">p</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 class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<p>For styling, use this CSS which contains all the styles needed for the entire app in your <code>App.css</code> file:</p>
<pre><code class="lang-css"><span class="hljs-keyword">@import</span> url(<span class="hljs-string">"https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;600;700&amp;display=swap"</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">box-sizing</span>: border-box;
}

<span class="hljs-selector-tag">html</span> {
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">62.5%</span>;
}

<span class="hljs-selector-pseudo">:root</span> {
  <span class="hljs-attribute">--text-color</span>: <span class="hljs-number">#9eb25d</span>;
  <span class="hljs-attribute">--bg-color</span>: <span class="hljs-built_in">rgba</span>(<span class="hljs-number">238</span>, <span class="hljs-number">252</span>, <span class="hljs-number">206</span>, <span class="hljs-number">0.4</span>);
}

<span class="hljs-selector-tag">body</span> {
  <span class="hljs-attribute">font-family</span>: <span class="hljs-string">"Space Grotesk"</span>, sans-serif;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">100</span>dvh;
  <span class="hljs-attribute">display</span>: grid;
  <span class="hljs-attribute">place-items</span>: center;
}

<span class="hljs-selector-class">.main__container</span> {
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">2rem</span>;
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">margin-top</span>: <span class="hljs-number">4rem</span>;

  <span class="hljs-attribute">flex-direction</span>: column;
  <span class="hljs-attribute">gap</span>: <span class="hljs-number">4rem</span>;

  <span class="hljs-attribute">align-items</span>: center;
  <span class="hljs-attribute">font-family</span>: <span class="hljs-string">"Space Grotesk"</span>, sans-serif;
  <span class="hljs-attribute">width</span>: max-content;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">8rem</span>;
  <span class="hljs-attribute">color</span>: <span class="hljs-built_in">var</span>(--text-color);
  <span class="hljs-attribute">background</span>: <span class="hljs-built_in">var</span>(--bg-color);
  <span class="hljs-attribute">box-shadow</span>: <span class="hljs-number">3px</span> <span class="hljs-number">3px</span> <span class="hljs-number">5px</span> <span class="hljs-built_in">rgba</span>(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0.2</span>);
}

<span class="hljs-selector-tag">h1</span> {
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">4rem</span>;
}
<span class="hljs-selector-class">.tab__header</span> {
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">list-style</span>: none;
  <span class="hljs-attribute">gap</span>: <span class="hljs-number">2rem</span>;
}

<span class="hljs-selector-class">.tab__header</span> <span class="hljs-selector-tag">li</span> {
  <span class="hljs-attribute">flex</span>: <span class="hljs-number">1</span>;
  <span class="hljs-attribute">cursor</span>: pointer;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">2rem</span>;
  <span class="hljs-attribute">border</span>: <span class="hljs-number">2px</span> solid <span class="hljs-built_in">var</span>(--text-color);
  <span class="hljs-attribute">text-align</span>: center;
  <span class="hljs-attribute">border-top-right-radius</span>: <span class="hljs-number">100%</span>;
  <span class="hljs-attribute">border-top-left-radius</span>: <span class="hljs-number">100%</span>;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">2rem</span>;
}

<span class="hljs-selector-class">.tab__container</span> {
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">flex-direction</span>: column;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">2rem</span>;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">80rem</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">2rem</span>;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">4rem</span>;
  <span class="hljs-attribute">box-shadow</span>: inset -<span class="hljs-number">3px</span> -<span class="hljs-number">3px</span> <span class="hljs-number">3px</span> <span class="hljs-built_in">rgba</span>(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0.2</span>),
    inset <span class="hljs-number">3px</span> <span class="hljs-number">3px</span> <span class="hljs-number">3px</span> <span class="hljs-built_in">rgba</span>(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0.2</span>);
  <span class="hljs-attribute">gap</span>: <span class="hljs-number">2rem</span>;
}

<span class="hljs-selector-class">.tab__content</span> {
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">2rem</span>;
  <span class="hljs-attribute">min-height</span>: <span class="hljs-number">25rem</span>;
  <span class="hljs-attribute">border</span>: <span class="hljs-number">2px</span> solid <span class="hljs-built_in">var</span>(--text-color);
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">justify-content</span>: space-between;
  <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">4rem</span>;
  <span class="hljs-attribute">background</span>: <span class="hljs-number">#fff</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">2rem</span>;
}

<span class="hljs-selector-class">.tab__content</span> <span class="hljs-selector-tag">img</span> {
  <span class="hljs-attribute">max-width</span>: <span class="hljs-number">31rem</span>;
  <span class="hljs-attribute">max-height</span>: <span class="hljs-number">20rem</span>;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
}

<span class="hljs-selector-class">.tab__content</span> <span class="hljs-selector-tag">p</span> {
  <span class="hljs-attribute">text-align</span>: center;
}

<span class="hljs-selector-class">.active</span> {
  <span class="hljs-attribute">background</span>: <span class="hljs-built_in">var</span>(--text-color);

  <span class="hljs-attribute">color</span>: <span class="hljs-number">#fff</span>;
  <span class="hljs-attribute">font-weight</span>: <span class="hljs-number">600</span>;
}

<span class="hljs-keyword">@media</span> screen <span class="hljs-keyword">and</span> (<span class="hljs-attribute">max-width:</span> <span class="hljs-number">1000px</span>) {
  <span class="hljs-selector-class">.main__container</span> {
    <span class="hljs-attribute">gap</span>: <span class="hljs-number">2rem</span>;
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">1rem</span>;
    <span class="hljs-attribute">width</span>: <span class="hljs-number">95%</span>;
    <span class="hljs-attribute">margin</span>: <span class="hljs-number">5rem</span> auto;
  }

  <span class="hljs-selector-tag">h1</span> {
    <span class="hljs-attribute">font-size</span>: <span class="hljs-number">3rem</span>;
  }

  <span class="hljs-selector-class">.tab__header</span> {
    <span class="hljs-attribute">flex-wrap</span>: wrap;
  }

  <span class="hljs-selector-class">.tab__content</span> {
    <span class="hljs-attribute">gap</span>: <span class="hljs-number">2rem</span>;
    <span class="hljs-attribute">min-height</span>: <span class="hljs-number">35rem</span>;
  }
  <span class="hljs-selector-class">.tab__header</span> <span class="hljs-selector-tag">li</span> {
    <span class="hljs-attribute">font-size</span>: <span class="hljs-number">1.6rem</span>;
  }

  <span class="hljs-selector-class">.tab__container</span> {
    <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">2rem</span>;
  }

  <span class="hljs-selector-class">.tab__content</span> <span class="hljs-selector-tag">img</span> {
    <span class="hljs-attribute">max-width</span>: <span class="hljs-number">150px</span>;
  }

  <span class="hljs-selector-class">.tab__content</span> <span class="hljs-selector-tag">p</span> {
    <span class="hljs-attribute">font-size</span>: <span class="hljs-number">1.6rem</span>;
  }
}
</code></pre>
<p>Or you can alternatively go here for the stylings: <a target="_blank" href="https://github.com/Daiveedjay/React-Tab/blob/main/src/App.css">CSS File</a></p>
<p>At the moment, your page should look like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/2-Initial-page-after-looping-over-data-array.png" alt="Image" width="600" height="400" loading="lazy">
<em>Initial page after looping over data array</em></p>
<h3 id="heading-how-to-implement-the-tab-functionality">How to Implement the Tab Functionality</h3>
<p>To create a tab component that functions smoothly, you need to manage which tab is currently active. Think of it as showing only one content section at a time. </p>
<p>To achieve this, start by establishing a 'state' in the App component. This state will keep track of the currently active tab.</p>
<pre><code class="lang-js">  <span class="hljs-keyword">const</span> [activeTab, setActiveTab] = useState(<span class="hljs-number">0</span>);
</code></pre>
<p>The active state is initialized with the index of the tab you want to start with.</p>
<p>Then it's used to show only the the data associated with that index.</p>
<pre><code class="lang-js"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">TabContent</span>(<span class="hljs-params">{ petData, activeTab }</span>) </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">"tab__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">"tab__content"</span>&gt;</span>
        {/ Using the active index to select a particular data /}
        <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{petData[activeTab].image}</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span> {petData[activeTab].fact}<span class="hljs-tag">&lt;/<span class="hljs-name">p</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>
  );
}
</code></pre>
<p>Which shows just the first item from the data array:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/3-Showing-one-data-from-the-array.png" alt="Image" width="600" height="400" loading="lazy">
<em>Showing one data item from the array</em></p>
<p>You can achieve the tab switching functionality by updating the state of the active tab using its setter function. </p>
<p>Start by passing the setter function and the active tab state into the tab buttons via props.</p>
<pre><code class="lang-js"><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> [activeTab, setActiveTab] = useState(<span class="hljs-number">0</span>);
  <span class="hljs-keyword">const</span> petData = [ <span class="hljs-comment">//...data ];</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">"main__container"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Choose your pet<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">TabButtons</span>
        <span class="hljs-attr">activeTab</span>=<span class="hljs-string">{activeTab}</span>
        <span class="hljs-attr">setActiveTab</span>=<span class="hljs-string">{setActiveTab}</span>
        <span class="hljs-attr">petData</span>=<span class="hljs-string">{petData}</span>
      /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">TabContent</span> <span class="hljs-attr">activeTab</span>=<span class="hljs-string">{activeTab}</span> <span class="hljs-attr">petData</span>=<span class="hljs-string">{petData}</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>Then use the setter function to set the value of the active state into the corresponding data via the index.</p>
<pre><code class="lang-js">
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">TabButtons</span>(<span class="hljs-params">{ petData, activeTab, setActiveTab }</span>) </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">"tab__header"</span>&gt;</span>
      {petData.map((item, index) =&gt; (
               <span class="hljs-tag">&lt;<span class="hljs-name">li</span>
          <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">tab__button</span>`}
          <span class="hljs-attr">key</span>=<span class="hljs-string">{item.animal}</span>
          <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> setActiveTab(index)}&gt;
          {item.animal}
        <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
      ))}
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<p>With that, your tab component works and can display dynamic data based on the button you click on. Congrats!</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/2-Testing-out-the-tab-functionality.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Testing out the tab functionality</em></p>
<p>To improve the UX, add an active class to the currently clicked tab using its index. This applies the active class to the tab whose index value is the same as the value stored in the active state.</p>
<pre><code class="lang-js"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">TabButtons</span>(<span class="hljs-params">{ petData, activeTab, setActiveTab }</span>) </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">"tab__header"</span>&gt;</span>
      {petData.map((item, index) =&gt; (
        <span class="hljs-tag">&lt;<span class="hljs-name">li</span>
          // <span class="hljs-attr">Adding</span> <span class="hljs-attr">an</span> <span class="hljs-attr">active</span> <span class="hljs-attr">class</span> <span class="hljs-attr">where</span> <span class="hljs-attr">the</span> <span class="hljs-attr">current</span> <span class="hljs-attr">index</span> <span class="hljs-attr">matches</span> <span class="hljs-attr">the</span> <span class="hljs-attr">currently</span> <span class="hljs-attr">active</span> <span class="hljs-attr">tab</span>
          <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`${<span class="hljs-attr">index</span> === <span class="hljs-string">activeTab</span> &amp;&amp; "<span class="hljs-attr">active</span>"} <span class="hljs-attr">tab__button</span>`}
          <span class="hljs-attr">key</span>=<span class="hljs-string">{item.animal}</span>
          <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> setActiveTab(index)}&gt;
          {item.animal}
        <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
      ))}
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<p>Which yields the following result:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/1-tab-functionality-after-adding-active-class-to-tab.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Tab functionality after adding active class to tab</em></p>
<h3 id="heading-how-to-optimize-the-tab-component">How to Optimize the Tab Component</h3>
<p>While your tab component seems ready to go, there are still modifications you can make to better enhance it in terms of performance. For this, you can use <a target="_blank" href="https://react.dev/learn/react-developer-tools">React Dev Tools</a>. </p>
<p>This is a browser extension which provides a ton of useful tools React developers can use to inspect and debug their applications. Head over to your browser web store and download the extension.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/3-Downloading-the-React-dev-tools.png" alt="Image" width="600" height="400" loading="lazy">
<em>Downloading React dev tools</em></p>
<p>After you install it, inspecting any React website from your browser dev tools shows two new tabs called <code>⚛️Components</code> and <code>⚛️Profiler</code>.</p>
<p>In this application, we’ll be using the Profiler, which is used to measure how many times the React application is rendered, how many components are rendered, and how much time the components take to be rendered.</p>
<p>For your application, inspect your React app and open up the profiler from the top right of your screen.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/IMG-20240116-WA0000.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Finding the profiler in dev tools</em></p>
<p>In your profiler, click on the blue record button and start a recording of your React app to track changes and renders.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/3-using-the-profiler-to-test-changes.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Using the profiler to test changes</em></p>
<p>The result from my end is a total of 0.6ms for the total render time with all 3 components re-rendering (<code>App</code> = 0.2ms, <code>TabButtons</code> = 0.3ms and <code>TabContent</code> = 0.1ms).</p>
<p>The entire render time is quite acceptable, but there is room for improvement.</p>
<p>With the profiler indicating that the app component triggered the re-render, let’s optimize our application to reduce excessive re-renders with the following steps.</p>
<p>Start by creating a <code>Tab</code> component and lifting the data array and the state into that <code>Tab</code> component. You do this because this is the component that consumes the data and state and not the App component.</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-keyword">const</span> petData = [
  {
    <span class="hljs-attr">animal</span>: <span class="hljs-string">"Cheetah"</span>,
    <span class="hljs-attr">fact</span>: <span class="hljs-string">"Cheetahs are the fastest land animals, capable of reaching speeds up to 75 mph."</span>,
    <span class="hljs-attr">image</span>: <span class="hljs-string">"../src/assets/6.svg"</span>,
  },
  {
    <span class="hljs-attr">animal</span>: <span class="hljs-string">"Koala"</span>,
    <span class="hljs-attr">fact</span>: <span class="hljs-string">"Koalas sleep around 20 hours a day and are known for their eucalyptus diet."</span>,
    <span class="hljs-attr">image</span>: <span class="hljs-string">"../src/assets/3.svg"</span>,
  },
  {
    <span class="hljs-attr">animal</span>: <span class="hljs-string">"Elephant"</span>,
    <span class="hljs-attr">fact</span>: <span class="hljs-string">"Elephants have the largest brains among land animals and demonstrate remarkable intelligence."</span>,
    <span class="hljs-attr">image</span>: <span class="hljs-string">"../src/assets/1.svg"</span>,
  },
  {
    <span class="hljs-attr">animal</span>: <span class="hljs-string">"Zebra"</span>,
    <span class="hljs-attr">fact</span>: <span class="hljs-string">"Zebras have distinctive black and white stripes that act as a natural defense against predators."</span>,
    <span class="hljs-attr">image</span>: <span class="hljs-string">"../src/assets/7.svg"</span>,
  },
  {
    <span class="hljs-attr">animal</span>: <span class="hljs-string">"Horse"</span>,
    <span class="hljs-attr">fact</span>: <span class="hljs-string">"Horses have excellent memory and are capable of recognizing human emotions."</span>,
    <span class="hljs-attr">image</span>: <span class="hljs-string">"../src/assets/5.svg"</span>,
  },
];

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Tab</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [activeTab, setActiveTab] = useState(<span class="hljs-number">0</span>);
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;&gt;</span><span class="hljs-tag">&lt;/&gt;</span></span>;
}
</code></pre>
<p>Then locally create the JSX for this project. This removes the need for creating excessive components just for JSX.</p>
<pre><code class="lang-js"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Tab</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [activeTab, setActiveTab] = useState(<span class="hljs-number">0</span>);
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"tab__header"</span>&gt;</span>
        {petData.map((item, index) =&gt; (
          <span class="hljs-tag">&lt;<span class="hljs-name">li</span>
            <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`${<span class="hljs-attr">index</span> === <span class="hljs-string">activeTab</span> &amp;&amp; "<span class="hljs-attr">active</span>"} <span class="hljs-attr">tab__button</span>`}
            <span class="hljs-attr">key</span>=<span class="hljs-string">{item.animal}</span>
            <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> setActiveTab(index)}&gt;
            {item.animal}
          <span class="hljs-tag">&lt;/<span class="hljs-name">li</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> <span class="hljs-attr">className</span>=<span class="hljs-string">"tab__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">"tab__content"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{petData[activeTab].image}</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</span> /&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span> {petData[activeTab].fact}<span class="hljs-tag">&lt;/<span class="hljs-name">p</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 class="hljs-tag">&lt;/&gt;</span></span>
  );
}
</code></pre>
<p>And now re-running the profiler with your new app structure yields the following:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/4-profiler-after-optimizing-app.png" alt="Image" width="600" height="400" loading="lazy">
<em>Profiler after optimizing app</em></p>
<p>As you can see, the new rendering time is 0.3ms, improving the speed by 50%, with the app component not re-rendering and the extra JSX elements removed.</p>
<p>It's important to note that this example is relative to the size of the tab component. In larger ones, it’s fairly common to see the tab component broken down into smaller components but in the same file.</p>
<h3 id="heading-how-to-animate-the-component">How to Animate the Component</h3>
<p>For animation, we’ll be using Framer Motion, an open-source animation library designed for React. It delivers a straightforward and expressive API for generating intricate animations. </p>
<p>For a more in-depth explanation of how the library works, check out this guide on <a target="_blank" href="https://www.freecodecamp.org/news/improve-user-experience-in-react-by-animating-routes-using-framer-motion/">using framer motion to animate routes in React</a>.</p>
<p>To use the library, start by installing it in your project using the prompt:</p>
<pre><code class="lang-bash">npm i framer-motion
</code></pre>
<p>Then import the required properties from the library.</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { AnimatePresence, motion } <span class="hljs-keyword">from</span> <span class="hljs-string">"framer-motion"</span>;
</code></pre>
<p>Next, make all the elements you want to animate motion elements.</p>
<pre><code class="lang-js"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Tab</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">motion.div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"tab__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">"tab__header"</span>&gt;</span>
            {petData.map((item, index) =&gt; (
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span>
                <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`${<span class="hljs-attr">index</span> === <span class="hljs-string">activeTab</span> &amp;&amp; "<span class="hljs-attr">active</span>"} <span class="hljs-attr">tab__button</span>`}
                <span class="hljs-attr">key</span>=<span class="hljs-string">{item.animal}</span>
                <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> setActiveTab(index)}&gt;
                {item.animal}
              <span class="hljs-tag">&lt;/<span class="hljs-name">li</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> <span class="hljs-attr">className</span>=<span class="hljs-string">"tab__content"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">motion.img</span>
              <span class="hljs-attr">src</span>=<span class="hljs-string">{petData[activeTab].image}</span>
              <span class="hljs-attr">alt</span>=<span class="hljs-string">""</span>
            /&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">motion.p</span>&gt;</span>
              {petData[activeTab].fact}
            <span class="hljs-tag">&lt;/<span class="hljs-name">motion.p</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">motion.div</span>&gt;</span>

    <span class="hljs-tag">&lt;/&gt;</span></span>
  );
}
</code></pre>
<p>Then create animation objects for the elements you want to animate. For your tab, this create a scale in animation for the image and a fade and slide animation for the text.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> contentVariants = {
  <span class="hljs-attr">initial</span>: { <span class="hljs-attr">y</span>: <span class="hljs-string">"100%"</span>, <span class="hljs-attr">opacity</span>: <span class="hljs-number">0</span> },
  <span class="hljs-attr">animate</span>: { <span class="hljs-attr">y</span>: <span class="hljs-string">"0"</span>, <span class="hljs-attr">opacity</span>: <span class="hljs-number">1</span> },
  <span class="hljs-attr">exit</span>: { <span class="hljs-attr">y</span>: <span class="hljs-string">"100%"</span>, <span class="hljs-attr">opacity</span>: <span class="hljs-number">0</span> },
};

<span class="hljs-keyword">const</span> imgVariants = {
  <span class="hljs-attr">initial</span>: { <span class="hljs-attr">scale</span>: <span class="hljs-number">0.1</span> },
  <span class="hljs-attr">animate</span>: { <span class="hljs-attr">scale</span>: <span class="hljs-number">1</span> },
  <span class="hljs-attr">exit</span>: { <span class="hljs-attr">scale</span>: <span class="hljs-number">0.1</span> },
};
</code></pre>
<p>After that, pass them into the JSX, specifying their initial, animated, and exit states. </p>
<pre><code class="lang-js"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Tab</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [activeTab, setActiveTab] = useState(<span class="hljs-number">0</span>);
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">motion.div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"tab__container"</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{activeTab}</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"tab__header"</span>&gt;</span>
            {petData.map((item, index) =&gt; (
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span>
                <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`${<span class="hljs-attr">index</span> === <span class="hljs-string">activeTab</span> &amp;&amp; "<span class="hljs-attr">active</span>"} <span class="hljs-attr">tab__button</span>`}
                <span class="hljs-attr">key</span>=<span class="hljs-string">{item.animal}</span>
                <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> setActiveTab(index)}&gt;
                {item.animal}
              <span class="hljs-tag">&lt;/<span class="hljs-name">li</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> <span class="hljs-attr">className</span>=<span class="hljs-string">"tab__content"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">motion.img</span>
              <span class="hljs-attr">src</span>=<span class="hljs-string">{petData[activeTab].image}</span>
              <span class="hljs-attr">alt</span>=<span class="hljs-string">""</span>
              <span class="hljs-attr">initial</span>=<span class="hljs-string">"initial"</span>
              <span class="hljs-attr">animate</span>=<span class="hljs-string">"animate"</span>
              <span class="hljs-attr">exit</span>=<span class="hljs-string">"exit"</span>
              <span class="hljs-attr">variants</span>=<span class="hljs-string">{imgVariants}</span>
              <span class="hljs-attr">transition</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">duration:</span> <span class="hljs-attr">0.5</span> }}
            /&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">motion.p</span>
              <span class="hljs-attr">variants</span>=<span class="hljs-string">{contentVariants}</span>
              <span class="hljs-attr">initial</span>=<span class="hljs-string">"initial"</span>
              <span class="hljs-attr">animate</span>=<span class="hljs-string">"animate"</span>
              <span class="hljs-attr">exit</span>=<span class="hljs-string">"exit"</span>
              <span class="hljs-attr">transition</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">duration:</span> <span class="hljs-attr">0.5</span> }}&gt;</span>
              {petData[activeTab].fact}
            <span class="hljs-tag">&lt;/<span class="hljs-name">motion.p</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">motion.div</span>&gt;</span>

    <span class="hljs-tag">&lt;/&gt;</span></span>
  );
}
</code></pre>
<p>Finally, wrap your component with the <code>AnimatePresence</code> component to detect when you switch between tabs to fire exit animations:</p>
<pre><code class="lang-js"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Tab</span>(<span class="hljs-params"></span>) </span>{

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">AnimatePresence</span> <span class="hljs-attr">mode</span>=<span class="hljs-string">"wait"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">motion.div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"tab__container"</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{activeTab}</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"tab__header"</span>&gt;</span>
            {petData.map((item, index) =&gt; (
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span>
                <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`${<span class="hljs-attr">index</span> === <span class="hljs-string">activeTab</span> &amp;&amp; "<span class="hljs-attr">active</span>"} <span class="hljs-attr">tab__button</span>`}
                <span class="hljs-attr">key</span>=<span class="hljs-string">{item.animal}</span>
                <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> setActiveTab(index)}&gt;
                {item.animal}
              <span class="hljs-tag">&lt;/<span class="hljs-name">li</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> <span class="hljs-attr">className</span>=<span class="hljs-string">"tab__content"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">motion.img</span>
              <span class="hljs-attr">src</span>=<span class="hljs-string">{petData[activeTab].image}</span>
              <span class="hljs-attr">alt</span>=<span class="hljs-string">""</span>
              <span class="hljs-attr">initial</span>=<span class="hljs-string">"initial"</span>
              <span class="hljs-attr">animate</span>=<span class="hljs-string">"animate"</span>
              <span class="hljs-attr">exit</span>=<span class="hljs-string">"exit"</span>
              <span class="hljs-attr">variants</span>=<span class="hljs-string">{imgVariants}</span>
              <span class="hljs-attr">transition</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">duration:</span> <span class="hljs-attr">0.5</span> }}
            /&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">motion.p</span>
              <span class="hljs-attr">variants</span>=<span class="hljs-string">{contentVariants}</span>
              <span class="hljs-attr">initial</span>=<span class="hljs-string">"initial"</span>
              <span class="hljs-attr">animate</span>=<span class="hljs-string">"animate"</span>
              <span class="hljs-attr">exit</span>=<span class="hljs-string">"exit"</span>
              <span class="hljs-attr">transition</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">duration:</span> <span class="hljs-attr">0.5</span> }}&gt;</span>
              {petData[activeTab].fact}
            <span class="hljs-tag">&lt;/<span class="hljs-name">motion.p</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">motion.div</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">AnimatePresence</span>&gt;</span>
    <span class="hljs-tag">&lt;/&gt;</span></span>
  );
}
</code></pre>
<p><strong>Note</strong>: Framer motion uses the key prop to detect changes between elements. The mode prop set to wait in <code>AnimatePresense</code> helps framer motion fire exit animations before entry animations.</p>
<p>And with that, your Tab component is fully functional and animated. Bravo! 🎈</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/tab-component-fully-functional-and-animated-.gif" alt="Image" width="600" height="400" loading="lazy">
<em>tabbed component fully functional and animated</em></p>
<p>For reference, here’s the full code:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { AnimatePresence, motion } <span class="hljs-keyword">from</span> <span class="hljs-string">"framer-motion"</span>;

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

<span class="hljs-keyword">const</span> petData = [
  {
    <span class="hljs-attr">animal</span>: <span class="hljs-string">"Cheetah"</span>,
    <span class="hljs-attr">fact</span>: <span class="hljs-string">"Cheetahs are the fastest land animals, capable of reaching speeds up to 75 mph."</span>,
    <span class="hljs-attr">image</span>: <span class="hljs-string">"../src/assets/6.svg"</span>,
  },
  {
    <span class="hljs-attr">animal</span>: <span class="hljs-string">"Koala"</span>,
    <span class="hljs-attr">fact</span>: <span class="hljs-string">"Koalas sleep around 20 hours a day and are known for their eucalyptus diet."</span>,
    <span class="hljs-attr">image</span>: <span class="hljs-string">"../src/assets/3.svg"</span>,
  },
  {
    <span class="hljs-attr">animal</span>: <span class="hljs-string">"Elephant"</span>,
    <span class="hljs-attr">fact</span>: <span class="hljs-string">"Elephants have the largest brains among land animals and demonstrate remarkable intelligence."</span>,
    <span class="hljs-attr">image</span>: <span class="hljs-string">"../src/assets/1.svg"</span>,
  },
  {
    <span class="hljs-attr">animal</span>: <span class="hljs-string">"Zebra"</span>,
    <span class="hljs-attr">fact</span>: <span class="hljs-string">"Zebras have distinctive black and white stripes that act as a natural defense against predators."</span>,
    <span class="hljs-attr">image</span>: <span class="hljs-string">"../src/assets/7.svg"</span>,
  },
  {
    <span class="hljs-attr">animal</span>: <span class="hljs-string">"Horse"</span>,
    <span class="hljs-attr">fact</span>: <span class="hljs-string">"Horses have excellent memory and are capable of recognizing human emotions."</span>,
    <span class="hljs-attr">image</span>: <span class="hljs-string">"../src/assets/5.svg"</span>,
  },
];

<span class="hljs-keyword">const</span> contentVariants = {
  <span class="hljs-attr">initial</span>: { <span class="hljs-attr">y</span>: <span class="hljs-string">"100%"</span>, <span class="hljs-attr">opacity</span>: <span class="hljs-number">0</span> },
  <span class="hljs-attr">animate</span>: { <span class="hljs-attr">y</span>: <span class="hljs-string">"0"</span>, <span class="hljs-attr">opacity</span>: <span class="hljs-number">1</span> },
  <span class="hljs-attr">exit</span>: { <span class="hljs-attr">y</span>: <span class="hljs-string">"100%"</span>, <span class="hljs-attr">opacity</span>: <span class="hljs-number">0</span> },
};

<span class="hljs-keyword">const</span> imgVariants = {
  <span class="hljs-attr">initial</span>: { <span class="hljs-attr">scale</span>: <span class="hljs-number">0.1</span> },
  <span class="hljs-attr">animate</span>: { <span class="hljs-attr">scale</span>: <span class="hljs-number">1</span> },
  <span class="hljs-attr">exit</span>: { <span class="hljs-attr">scale</span>: <span class="hljs-number">0.1</span> },
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Tab</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [activeTab, setActiveTab] = useState(<span class="hljs-number">0</span>);
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">AnimatePresence</span> <span class="hljs-attr">mode</span>=<span class="hljs-string">"wait"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">motion.div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"tab__container"</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{activeTab}</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"tab__header"</span>&gt;</span>
            {petData.map((item, index) =&gt; (
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span>
                <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`${<span class="hljs-attr">index</span> === <span class="hljs-string">activeTab</span> &amp;&amp; "<span class="hljs-attr">active</span>"} <span class="hljs-attr">tab__button</span>`}
                <span class="hljs-attr">key</span>=<span class="hljs-string">{item.animal}</span>
                <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> setActiveTab(index)}&gt;
                {item.animal}
              <span class="hljs-tag">&lt;/<span class="hljs-name">li</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> <span class="hljs-attr">className</span>=<span class="hljs-string">"tab__content"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">motion.img</span>
              <span class="hljs-attr">src</span>=<span class="hljs-string">{petData[activeTab].image}</span>
              <span class="hljs-attr">alt</span>=<span class="hljs-string">""</span>
              <span class="hljs-attr">initial</span>=<span class="hljs-string">"initial"</span>
              <span class="hljs-attr">animate</span>=<span class="hljs-string">"animate"</span>
              <span class="hljs-attr">exit</span>=<span class="hljs-string">"exit"</span>
              <span class="hljs-attr">variants</span>=<span class="hljs-string">{imgVariants}</span>
              <span class="hljs-attr">transition</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">duration:</span> <span class="hljs-attr">0.5</span> }}
            /&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">motion.p</span>
              <span class="hljs-attr">variants</span>=<span class="hljs-string">{contentVariants}</span>
              <span class="hljs-attr">initial</span>=<span class="hljs-string">"initial"</span>
              <span class="hljs-attr">animate</span>=<span class="hljs-string">"animate"</span>
              <span class="hljs-attr">exit</span>=<span class="hljs-string">"exit"</span>
              <span class="hljs-attr">transition</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">duration:</span> <span class="hljs-attr">0.5</span> }}&gt;</span>
              {petData[activeTab].fact}
            <span class="hljs-tag">&lt;/<span class="hljs-name">motion.p</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">motion.div</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">AnimatePresence</span>&gt;</span>
    <span class="hljs-tag">&lt;/&gt;</span></span>
  );
}
</code></pre>
<h2 id="heading-other-methods-you-can-use-to-fine-tune-for-high-performance">Other Methods You Can Use to Fine-Tune for High Performance</h2>
<p>While your React tab component is functional and animated, there are opportunities for further optimization to ensure high performance, especially in scenarios involving larger datasets or asynchronous data fetching. Let's explore some strategies to fine-tune your tab component.</p>
<h3 id="heading-data-considerations">Data Considerations</h3>
<ul>
<li>Size of the Tab Component: Check the size of your tab component, especially if dealing with a large amount of data. Consider lazy-loading or pagination to improve initial rendering times.</li>
<li>Asynchronous Data Loading: If your data is asynchronous, implement loading states to enhance user experience. Optimize the rendering logic to handle data loading efficiently.</li>
</ul>
<h3 id="heading-react-profiler">React Profiler</h3>
<ul>
<li>Identifying and Reducing Unnecessary Re-renders: Outside leveraging React DevTools Profiler to analyze component rendering behaviour, use React hooks like React.memo and React.callback to optimize and cache your data.</li>
</ul>
<h3 id="heading-component-structure">Component Structure</h3>
<ul>
<li>Granular Component Structure: For larger tab components, consider breaking down the structure into smaller, granular components. This allows for better maintainability and can improve rendering performance.</li>
</ul>
<h3 id="heading-code-splitting">Code Splitting</h3>
<ul>
<li>Dynamic Imports for Code Splitting: Implement dynamic imports for code splitting, especially if your React application becomes more complex. This ensures that only the necessary code loads when a specific tab is selected.</li>
</ul>
<h3 id="heading-responsive-design">Responsive Design</h3>
<ul>
<li>Optimizing for Different Viewports: Ensure your tab component is responsive to different screen sizes. Consider media queries and adaptive design to provide an optimal experience across various devices.</li>
</ul>
<h3 id="heading-browser-caching">Browser Caching</h3>
<ul>
<li>Optimizing Assets with Browser Caching: Leverage browser caching for static assets, such as images, to reduce load times. Consider optimizing and compressing images to cut their impact on performance.</li>
</ul>
<h3 id="heading-testing-and-profiling">Testing and Profiling</h3>
<ul>
<li>Continuous Testing and Profiling: Test your tab component under various conditions and profiles. Use tools like Lighthouse or Web Vitals to track performance metrics and address any issues that may arise.</li>
</ul>
<p>By implementing these strategies, you can elevate your React tab component from merely functional to highly performant, ensuring a smooth user experience across different scenarios and datasets.</p>
<p>Here’s a link to the repository: <a target="_blank" href="https://github.com/Daiveedjay/React-Tab">GitHub</a></p>
<p>And the live version: <a target="_blank" href="https://react-tabbed-component-fcc.netlify.app/">Live Demo</a></p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>You've successfully built React tabs that are more than just functional – they're optimized for a smooth user experience. From setting up the environment to adding animations, you've covered the essentials.</p>
<p>As you refine and optimize your tabs, remember they play a crucial role in user navigation. Keep coding and may your React tabs deliver a dependable and user-friendly experience.</p>
<p>Happy coding!🌟</p>
<h3 id="heading-contact-information">Contact Information</h3>
<p>Want to connect or contact me? Feel free to hit me up on the following:</p>
<ul>
<li>Twitter / X: <a target="_blank" href="https://twitter.com/JajaDavid8">@jajadavid8</a></li>
<li>LinkedIn: <a target="_blank" href="https://www.linkedin.com/in/david-jaja-8084251b4/">David Jaja</a></li>
<li>Email: Jajadavidjid@gmail.com</li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Use URLs for State Management in React ]]>
                </title>
                <description>
                    <![CDATA[ For years, URLs have been synonymous with web navigation. But the tide is turning, especially with the emergence of single-page applications. In the React universe, URLs are stepping up to play a pivotal role in state management. This article will gu... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-use-urls-for-state-management-in-react/</link>
                <guid isPermaLink="false">66bb890b7a6500a14ba5b769</guid>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ routing ]]>
                    </category>
                
                    <category>
                        <![CDATA[ State Management  ]]>
                    </category>
                
                    <category>
                        <![CDATA[ url ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ David Jaja ]]>
                </dc:creator>
                <pubDate>Fri, 06 Oct 2023 17:50:28 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/10/Article-Cover.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>For years, URLs have been synonymous with web navigation. But the tide is turning, especially with the emergence of single-page applications. In the React universe, URLs are stepping up to play a pivotal role in state management.</p>
<p>This article will guide you through the transformative journey of URLs as state managers in the context of React applications. </p>
<h3 id="heading-prerequisites">Prerequisites</h3>
<ul>
<li>Fundamentals of HTML and CSS</li>
<li>Fundamentals of ES6 JavaScript</li>
<li>Fundamentals of React, React Router and React Hooks.</li>
</ul>
<h2 id="heading-the-evolution-of-state-management-in-react">The Evolution of State Management in React</h2>
<p>Let's journey through the past:</p>
<ul>
<li><strong>setState</strong>: In the early days of React, many relied on component state, especially within <a target="_blank" href="https://react.dev/reference/react/Component#defining-a-class-component">class components</a>. It was straightforward to manage component-specific data. But it wasn't ideal for larger applications.</li>
<li><strong>Redux &amp; MobX</strong>: As applications grew in complexity, tools like <a target="_blank" href="https://redux.js.org/">Redux</a> and <a target="_blank" href="https://mobx.js.org/README.html">MobX</a> emerged. They centralized data management, making it easier to handle app-wide data.</li>
<li><strong>Context API &amp; Hooks</strong>: React's own <a target="_blank" href="https://react.dev/reference/react/useContext">Context API</a>, combined with the advent of hooks, brought about a more native way to manage the global state without adding extra libraries.</li>
</ul>
<h2 id="heading-managing-state-with-urls">Managing State with URLs</h2>
<p>At first, using a URL for managing state might seem unusual. But as you explore further, you'll discover several clear benefits:</p>
<ul>
<li><strong>Save Your Spot</strong>: By keeping state in the URL, your webpage remembers your place. So, if you bookmark a page, it will look the same when you come back to it later.</li>
<li><strong>Easy Sharing</strong>: If you're looking at something specific on a page, like a product or a chart, you can share the URL. Anyone who clicks it will see exactly what you’re seeing, making collaboration a breeze.</li>
<li><strong>Troubleshoot with Ease</strong>: Developers can find and fix issues faster because the URL shows the state of the app. They can see problems just by clicking on the shared link.</li>
</ul>
<p>In short, using URLs in this way helps keep your spot, share specific views, and makes problem-solving smoother for developers.</p>
<h2 id="heading-how-to-implement-url-based-state-management">How to Implement URL-based State Management</h2>
<p>Considering the size of this section, here’s everything you’ll learn.</p>
<ol>
<li>How to Set Up the Environment</li>
<li>Clearing the clutter</li>
<li>Project Breakdown / Analysis</li>
<li>Install the Necessary Dependencies</li>
<li>How to Fetch the Data and Design the UI</li>
<li>How to Store State in the URL</li>
<li>How to Read the State Stored in the URL</li>
<li>How to Customize the Product Page</li>
</ol>
<h3 id="heading-how-to-set-up-the-environment">How to Set Up the Environment</h3>
<p>Open your inbuilt terminal or code editor’s terminal (preferably) and run the following:</p>
<pre><code class="lang-bash">npm create vite@latest
</code></pre>
<p>This command uses <a target="_blank" href="https://vitejs.dev/guide/">Vite</a> (a lightweight tool that is used for building fast and optimized web applications) to scaffold a web app environment. Navigate down using your arrow keys and select React.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/10/02-Selecting-React.png" alt="Image" width="600" height="400" loading="lazy">
<em>Selecting React from Vite Setup</em></p>
<p>Then select your preferred language combination – I’ll be using plain JS.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/10/03-Selecting-JS.png" alt="Image" width="600" height="400" loading="lazy">
<em>Selecting Language in React</em></p>
<p>Next, move into your react folder using the cd “project-name” folder and run <code>npm install</code> to install all the project’s dependencies.</p>
<p>Finally, start the development server by running <code>npm run dev</code> and going to the respective URL (<a target="_blank" href="http://localhost:5173/">http://localhost:5173/</a>).</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/10/04-dev-server-running.png" alt="Image" width="600" height="400" loading="lazy">
<em>Dev Server running</em></p>
<h3 id="heading-clearing-the-clutter">Clearing the clutter</h3>
<p>Make sure to clear the contents of all the CSS files and delete the <code>App.css</code> as you’ll need only 1 style file. Then, clear the contents of the <code>App</code> component and replace it with basic JSX content.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/10/05-clutter-cleared.png" alt="Image" width="600" height="400" loading="lazy">
<em>Clutter Cleared in Dev Environment</em></p>
<p>This returns a clear page on your local server that looks like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/10/06-clear-server-page.png" alt="Image" width="600" height="400" loading="lazy">
<em>Clear Server page</em></p>
<h3 id="heading-project-breakdown-analysis">Project breakdown / analysis</h3>
<p>The project involves getting data from an API and persisting that data globally via the URL to be accessible across many components/pages.</p>
<p>A relatable example is when you’re on your favourite e-commerce site, you may see this cool gadget and want to share it with your friend.</p>
<p>You usually share the link from the browser to your friend’s social media DM which they can use to view the same product without any fuss by opening the link you sent to them.</p>
<p>Here’s a sneaky peek at the project we're going to build: 😉</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/10/1-sneaky-peek.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Sneaky peek of complete project</em></p>
<p>Intrigued?🌚 Let’s dive in then.</p>
<h3 id="heading-install-the-necessary-dependencies">Install the necessary dependencies</h3>
<p>Before you put anything on the page, you must first fully configure your development environment with the necessary dependencies.</p>
<ul>
<li><a target="_blank" href="https://www.npmjs.com/package/json-server">json-server</a>: This package hosts your data on a local server, enabling you to fetch it like an external API.</li>
<li><a target="_blank" href="https://www.npmjs.com/package/react-router">react-router</a>: This package enables React to create SPAs that allow navigating without refreshing the page.</li>
</ul>
<pre><code class="lang-bash">npm i json-server react-router-dom
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/10/08-installing-dependencies-1.png" alt="Image" width="600" height="400" loading="lazy">
<em>Installing dependencies</em></p>
<ul>
<li>Then download the JSON data from this <a target="_blank" href="https://github.com/Daiveedjay/URL-State-Management/tree/main/data">GitHub(json-data)</a>, and the assets from this <a target="_blank" href="https://github.com/Daiveedjay/URL-State-Management/tree/main/public/assets">GitHub(assets-data)</a>.</li>
</ul>
<p>Now create a data folder in your root project directory and place the JSON file inside. Then create an assets folder in your public directory and place all images in that assets folder.</p>
<p>Your current folder structure should be like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/10/07-folder-structure-after-downloading-files.png" alt="Image" width="600" height="400" loading="lazy">
<em>Folder structure after downloading files</em></p>
<p>Next, modify your package.json file by adding a script which starts up the json-server</p>
<pre><code class="lang-json"><span class="hljs-string">"server"</span>: <span class="hljs-string">"json-server --watch data/products.json --port 9000 "</span>
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/10/09-adding-a-server-script.png" alt="Image" width="600" height="400" loading="lazy">
<em>Adding server script to package.json</em></p>
<p>After that, open your terminal and start up the server with <code>npm run server</code>:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/10/10-starting-data-server.png" alt="Image" width="600" height="400" loading="lazy">
<em>Starting data server</em></p>
<p>With this, your server is running and the content of your JSON file can be accessed through the URL provided.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/10/11-data-on-browser.png" alt="Image" width="600" height="400" loading="lazy">
<em>Data on Browser</em></p>
<p>Ps: If you want to view JSON files in the browser like I do, download the browser extension – <a target="_blank" href="https://chrome.google.com/webstore/detail/json-viewer/gbmdgpbipfallnflgajpaliibnhdgobh">JSON Viewer</a>.</p>
<h3 id="heading-how-to-fetch-the-data-and-design-the-ui">How to fetch the data and design the UI</h3>
<p>Start by creating a HomePage component and importing it into the App component. This component will contain all the data in the first screen you saw earlier.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/10/12-importing-the-homepage.png" alt="Image" width="600" height="400" loading="lazy">
<em>Importing the Homepage</em></p>
<p>In the <code>HomePage</code> component, use a <code>useEffect</code> hook to fetch all the data from your local API.</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">HomePage</span>(<span class="hljs-params"></span>) </span>{
  useEffect(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">fetchData</span>(<span class="hljs-params"></span>) </span>{

      <span class="hljs-keyword">try</span>{
      <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">"http://localhost:9000/products"</span>);
      <span class="hljs-keyword">const</span> clothesData = <span class="hljs-keyword">await</span> res.json();
      <span class="hljs-built_in">console</span>.log(clothesData);   
      }
      <span class="hljs-keyword">catch</span> (error) {  <span class="hljs-built_in">console</span>.log(error);}
      }
    fetchData();
  }, []);

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">main</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"homepage"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Homepage of my Dummy Product Page<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span></span>
  );
}
</code></pre>
<p>At the moment, you can already view the data fetched in the console.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/10/13-evidence-of-fetching-data.png" alt="Image" width="600" height="400" loading="lazy">
<em>Evidence of data fetching</em></p>
<p>Next, store your data in a state using the <code>useState</code> hook and populate your interface with that data.</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { useEffect, useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">HomePage</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [products, setProducts] = useState([]);

  useEffect(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">fetchData</span>(<span class="hljs-params"></span>) </span>{
      <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">"http://localhost:9000/products"</span>);
        <span class="hljs-keyword">const</span> clothesData = <span class="hljs-keyword">await</span> res.json();
        <span class="hljs-built_in">console</span>.log(clothesData);
        <span class="hljs-comment">//Storing happens here</span>
        setProducts(clothesData);
      } <span class="hljs-keyword">catch</span> (error) {
        <span class="hljs-built_in">console</span>.log(error);
      }
    }
    fetchData();
  }, []);

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">main</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"homepage"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Homepage of my Dummy Product Page<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"products__list"</span>&gt;</span>
        {products.map((product) =&gt; (
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span>
            <span class="hljs-attr">key</span>=<span class="hljs-string">{product.id}</span>
                      <span class="hljs-attr">className</span>=<span class="hljs-string">"product__item"</span>
          &gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">loading</span>=<span class="hljs-string">"lazy"</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{product.imageUrl}</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</span> /&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>{product.itemName}<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>
        ))}
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span></span>
  );
}
</code></pre>
<p>All the styling required in this project is in this <a target="_blank" href="https://github.com/Daiveedjay/URL-State-Management/blob/main/src/index.css">CSS file</a>. Alternatively, you can paste these stylings in your index.css, which gives the same result.</p>
<pre><code class="lang-css"><span class="hljs-keyword">@import</span> url(<span class="hljs-string">"https://fonts.googleapis.com/css2?family=Nunito:wght@400;700&amp;display=swap"</span>);

*,
<span class="hljs-selector-pseudo">::before</span>,
<span class="hljs-selector-pseudo">::after</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">box-sizing</span>: border-box;
}
<span class="hljs-selector-tag">html</span> {
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">62.5%</span>;
}
<span class="hljs-selector-tag">body</span> {
  <span class="hljs-attribute">font-family</span>: <span class="hljs-string">"Nunito"</span>, sans-serif;
}

<span class="hljs-selector-tag">h1</span> {
  <span class="hljs-attribute">text-align</span>: center;
  <span class="hljs-attribute">font-weight</span>: <span class="hljs-number">700</span>;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">3rem</span>;

  &amp; span {
    <span class="hljs-attribute">cursor</span>: pointer;
    <span class="hljs-attribute">margin-right</span>: <span class="hljs-number">3rem</span>;
  }
}

<span class="hljs-selector-tag">a</span>,
<span class="hljs-selector-tag">h3</span> {
  <span class="hljs-attribute">text-decoration</span>: none;
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#a04000</span>;
}

<span class="hljs-selector-tag">img</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
  <span class="hljs-attribute">display</span>: block;
  <span class="hljs-attribute">transition</span>: all ease-in <span class="hljs-number">0.3s</span>;
}

<span class="hljs-selector-class">.homepage</span> {
  <span class="hljs-attribute">min-height</span>: <span class="hljs-number">100vh</span>;
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">align-items</span>: center;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">1rem</span>;
  <span class="hljs-attribute">flex-direction</span>: column;
  <span class="hljs-attribute">gap</span>: <span class="hljs-number">3rem</span>;

  &amp; &gt; * {
    <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
  }
}

<span class="hljs-selector-class">.products__list</span> {
  <span class="hljs-attribute">column-count</span>: <span class="hljs-number">1</span>;
  <span class="hljs-attribute">column-gap</span>: <span class="hljs-number">2rem</span>;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">2rem</span>;

  &amp; &gt; * {
    <span class="hljs-attribute">break-inside</span>: avoid;
    <span class="hljs-attribute">margin-bottom</span>: <span class="hljs-number">2rem</span>;
  }

  &amp; <span class="hljs-selector-class">.product__item</span> {
    <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">1rem</span>;
    <span class="hljs-attribute">overflow</span>: hidden;
    <span class="hljs-attribute">display</span>: block;
    <span class="hljs-attribute">position</span>: relative;
    <span class="hljs-attribute">transition</span>: all ease-in <span class="hljs-number">0.3s</span>;

    &amp; h2 {
      <span class="hljs-attribute">background</span>: <span class="hljs-number">#fff</span>;
      <span class="hljs-attribute">bottom</span>: <span class="hljs-number">5px</span>;
      <span class="hljs-attribute">left</span>: <span class="hljs-number">5px</span>;
      <span class="hljs-attribute">padding</span>: <span class="hljs-number">0.5rem</span> <span class="hljs-number">1rem</span>;
      <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">5px</span>;
      <span class="hljs-attribute">z-index</span>: <span class="hljs-number">2</span>;
      <span class="hljs-attribute">position</span>: absolute;
      <span class="hljs-attribute">transition</span>: all ease-in <span class="hljs-number">0.3s</span>;
    }

    &amp;<span class="hljs-selector-pseudo">:hover</span> <span class="hljs-selector-tag">img</span> {
      <span class="hljs-attribute">scale</span>: <span class="hljs-number">1.1</span>;
    }

    &amp;<span class="hljs-selector-pseudo">:hover</span> <span class="hljs-selector-tag">h2</span> {
      <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">translate</span>(<span class="hljs-number">10px</span>, -<span class="hljs-number">10px</span>);
    }
  }
}

<span class="hljs-selector-class">.single__product</span> {
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">flex-direction</span>: column;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">2rem</span>;
  <span class="hljs-attribute">gap</span>: <span class="hljs-number">4rem</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">1rem</span>;
  <span class="hljs-attribute">overflow</span>: hidden;

  &amp; section {
    <span class="hljs-attribute">display</span>: flex;
    <span class="hljs-attribute">justify-content</span>: center;
    <span class="hljs-attribute">flex-direction</span>: column;

    &amp; figure {
      <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">1rem</span>;
      <span class="hljs-attribute">overflow</span>: hidden;

      &amp; .product__img {
        <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
      }
    }

    &amp; <span class="hljs-selector-tag">aside</span> {
      <span class="hljs-attribute">display</span>: flex;
      <span class="hljs-attribute">flex-direction</span>: column;
      <span class="hljs-attribute">justify-content</span>: flex-end;
      <span class="hljs-attribute">padding</span>: <span class="hljs-number">1.5rem</span>;

      &amp; &gt; h2 {
        <span class="hljs-attribute">font-size</span>: <span class="hljs-number">2.5rem</span>;
      }
      &amp; &gt; <span class="hljs-selector-tag">h3</span> {
        <span class="hljs-attribute">font-size</span>: <span class="hljs-number">1.6rem</span>;
      }
      &amp; <span class="hljs-selector-tag">span</span> {
        <span class="hljs-attribute">background</span>: <span class="hljs-built_in">rgba</span>(<span class="hljs-number">160</span>, <span class="hljs-number">64</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0.5</span>);
        <span class="hljs-attribute">padding-inline</span>: <span class="hljs-number">1rem</span>;
        <span class="hljs-attribute">align-self</span>: flex-start;
      }
    }
  }
}

<span class="hljs-comment">/* Small devices (portrait tablets and large phones, 600px and up) */</span>
<span class="hljs-keyword">@media</span> <span class="hljs-keyword">only</span> screen <span class="hljs-keyword">and</span> (<span class="hljs-attribute">min-width:</span> <span class="hljs-number">600px</span>) {
  <span class="hljs-selector-class">.products__list</span> {
    <span class="hljs-attribute">column-count</span>: <span class="hljs-number">2</span>;
  }

  <span class="hljs-selector-class">.single__product</span> {
    &amp; section {
      <span class="hljs-attribute">flex-direction</span>: row;

      &amp; .product__img {
        <span class="hljs-attribute">max-width</span>: <span class="hljs-number">300px</span>;
      }
    }
  }
}

<span class="hljs-comment">/* Medium devices (landscape tablets, 768px and up) */</span>
<span class="hljs-keyword">@media</span> <span class="hljs-keyword">only</span> screen <span class="hljs-keyword">and</span> (<span class="hljs-attribute">min-width:</span> <span class="hljs-number">768px</span>) {
  <span class="hljs-selector-class">.homepage</span> {
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">2rem</span> <span class="hljs-number">4rem</span>;
  }
  <span class="hljs-selector-class">.products__list</span> {
    <span class="hljs-attribute">column-count</span>: <span class="hljs-number">3</span>;
  }
}
</code></pre>
<p>At the moment, your home page should already look identical to the demo version.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/10/14-page-with-styings-applied.png" alt="Image" width="600" height="400" loading="lazy">
<em>Home page with styles added</em></p>
<h3 id="heading-how-to-store-state-in-the-url">How to store state in the URL</h3>
<p>In order to manage and share state across multiple pages using the URL, you first need to define routes using the react-router package.</p>
<p>Start by creating a route for the homepage:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { BrowserRouter, Route, Routes } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-router-dom"</span>;

<span class="hljs-keyword">import</span> HomePage <span class="hljs-keyword">from</span> <span class="hljs-string">"./HomePage"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</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">BrowserRouter</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">index</span> <span class="hljs-attr">element</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">HomePage</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">BrowserRouter</span>&gt;</span></span>
  );
}
</code></pre>
<ul>
<li>The <strong>BrowserRouter</strong> component wraps your entire application or the part of your app where you want to use routing.</li>
<li>The <strong>Routes</strong> component wraps all your <strong>Route</strong> components and is responsible for rendering the first route that matches the current location. </li>
<li>The <strong>Route</strong> component represents a single route in your application.</li>
</ul>
<p>Next, create a <code>ProductItem</code> component responsible for showing a single item and its equivalent route.</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { BrowserRouter, Route, Routes } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-router-dom"</span>;

<span class="hljs-keyword">import</span> HomePage <span class="hljs-keyword">from</span> <span class="hljs-string">"./Homepage"</span>;
<span class="hljs-keyword">import</span> ProductItem <span class="hljs-keyword">from</span> <span class="hljs-string">"./ProductItem"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</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">BrowserRouter</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">index</span> <span class="hljs-attr">element</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">HomePage</span> /&gt;</span>} /&gt;
         <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"product"</span> <span class="hljs-attr">element</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">ProductItem</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">BrowserRouter</span>&gt;</span></span>
  );
}
</code></pre>
<p>To view the <code>ProductItem</code> component, head over to your <code>HomePage</code> and wrap each individual product with a <code>Link</code> element pointing to the product page with their unique ID.</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { useEffect, useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { Link } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-router-dom"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">HomePage</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [products, setProducts] = useState([]);

  useEffect(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">fetchData</span>(<span class="hljs-params"></span>) </span>{
      <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">"http://localhost:9000/products"</span>);

      <span class="hljs-keyword">const</span> clothesData = <span class="hljs-keyword">await</span> res.json();
      <span class="hljs-built_in">console</span>.log(clothesData);
      setProducts(clothesData);
    }
    fetchData();
  }, []);

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">main</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"homepage"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Homepage of my Dummy Product Page<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"products__list"</span>&gt;</span>
        {products.map((product) =&gt; (
          <span class="hljs-tag">&lt;<span class="hljs-name">Link</span>
            <span class="hljs-attr">key</span>=<span class="hljs-string">{product.id}</span>
           // <span class="hljs-attr">Moving</span> <span class="hljs-attr">to</span> <span class="hljs-attr">the</span> <span class="hljs-attr">product</span> <span class="hljs-attr">page</span>
           <span class="hljs-attr">to</span>=<span class="hljs-string">{</span>`/<span class="hljs-attr">product</span>?<span class="hljs-attr">id</span>=<span class="hljs-string">${product.id}</span>`}
            <span class="hljs-attr">className</span>=<span class="hljs-string">"product__item"</span>
          &gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">loading</span>=<span class="hljs-string">"lazy"</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{product.imageUrl}</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</span> /&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>{product.itemName}<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">Link</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">main</span>&gt;</span></span>
  );
}
</code></pre>
<p>Clicking on any product now routes you to the product page and shows the <code>ProductItem</code> component.</p>
<p>On closer observation, you may notice that the id of each item is appended to the URL via its id property (for example: product?id=12345678).  This implies that you have successfully stored the id state to the URL.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/10/02-confirming-id-state-shared.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<h3 id="heading-how-to-read-the-state-stored-in-the-url">How to read the state stored in the URL</h3>
<p>In order to show data for each product, you have to read the state stored in the URL.</p>
<p>To implement this, start by creating a new custom hook (this helps for reusability). In your custom hook, import the <code>useSearchParams</code> hook.</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { useSearchParams } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-router-dom"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">useURLID</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [searchParams] = useSearchParams();
}
</code></pre>
<p>The <code>useSearchParams</code> hook allows you to interact with the query parameters of the URL (part of the URL that comes after the ? as seen in your URL earlier).</p>
<p>In order to retrieve the values from the URL, use the <code>get</code> method and pass in the name of the value you want to retrieve, in this case, the <code>id</code>.</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { useSearchParams } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-router-dom"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">useURLID</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [searchParams] = useSearchParams();
  <span class="hljs-keyword">const</span> id = searchParams.get(<span class="hljs-string">"id"</span>);
  <span class="hljs-keyword">return</span> { id };
}
</code></pre>
<p>To test out your hook, import it into the <code>ProductItem</code> page and extract the values.</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { useURLID } <span class="hljs-keyword">from</span> <span class="hljs-string">"./useURLID"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ProductItem</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> { id } = useURLID();
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>Product Item {id}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>;
}
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/10/2-confirming-id-state-shared.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p>And voilà! Your id state is now global and can used by any component in your app. Bravo!</p>
<h3 id="heading-how-to-customize-the-product-page">How to customize the Product Page</h3>
<p>In order to fully achieve what was shown in the demo, perform another fetch based on the id to get the data for that product.</p>
<p>Start by creating states to store the data and account for the data loading.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> [singleProduct, setSingleProduct] = useState({});
<span class="hljs-keyword">const</span> [loading, setLoading] = useState(<span class="hljs-literal">false</span>);
</code></pre>
<p>Then use a <code>useEffect</code> hook to fetch and store the data based on the unique product id.</p>
<pre><code class="lang-js">  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">fetchData</span>(<span class="hljs-params"></span>) </span>{
      setLoading(<span class="hljs-literal">true</span>);
      <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">`http://localhost:9000/products/<span class="hljs-subst">${id}</span>`</span>);

        <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> res.json();

        setSingleProduct(data);
      } <span class="hljs-keyword">catch</span> (error) {
        <span class="hljs-built_in">console</span>.log(error);
      } <span class="hljs-keyword">finally</span> {
        setLoading(<span class="hljs-literal">false</span>);
      }
    }
    fetchData();
  }, [id]);
</code></pre>
<p>Next, use the data received to populate the interface.</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { useEffect, useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { useURLID } <span class="hljs-keyword">from</span> <span class="hljs-string">"./useURLID"</span>;


<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ProductItem</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> { id } = useURLID();
  <span class="hljs-keyword">const</span> [singleProduct, setSingleProduct] = useState({});
  <span class="hljs-keyword">const</span> [loading, setLoading] = useState(<span class="hljs-literal">false</span>);

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">fetchData</span>(<span class="hljs-params"></span>) </span>{
      setLoading(<span class="hljs-literal">true</span>);
      <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">`http://localhost:8000/products/<span class="hljs-subst">${id}</span>`</span>);

        <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> res.json();

        setSingleProduct(data);
      } <span class="hljs-keyword">catch</span> (error) {
        <span class="hljs-built_in">console</span>.log(error);
      } <span class="hljs-keyword">finally</span> {
        setLoading(<span class="hljs-literal">false</span>);
      }
    }
    fetchData();
  }, [id]);



  <span class="hljs-comment">// If loading, display the loading div</span>
  <span class="hljs-keyword">if</span> (loading) <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>Loading...<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>;

  <span class="hljs-comment">// If not loading, display the product details</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">"single__product"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>
               <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>
          {singleProduct.itemName} Page id: {id}
        <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">section</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">figure</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"product__img-container"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">img</span>
            <span class="hljs-attr">className</span>=<span class="hljs-string">"product__img"</span>
            <span class="hljs-attr">src</span>=<span class="hljs-string">{singleProduct.imageUrl}</span>
            <span class="hljs-attr">alt</span>=<span class="hljs-string">"Image"</span>
          /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">figure</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">aside</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>{singleProduct.itemName}<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>{singleProduct.notes}<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">h4</span>&gt;</span>
            Category: <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>{singleProduct.type}<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">h4</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>
            Width: <span class="hljs-tag">&lt;<span class="hljs-name">strong</span>&gt;</span>{singleProduct?.size?.width}<span class="hljs-tag">&lt;/<span class="hljs-name">strong</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>
            Length: <span class="hljs-tag">&lt;<span class="hljs-name">strong</span>&gt;</span>{singleProduct?.size?.length}<span class="hljs-tag">&lt;/<span class="hljs-name">strong</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">aside</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">section</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<p>Finally, account for easy navigation by providing a back button to go to the home page. You can do this using the <code>useNavigate</code> hook in react-router. This hook provides a function that allows you to programmatically navigate to other parts of your application. </p>
<p>Simply import the <code>useNavigate</code> hook, and initialize it with a variable like this:</p>
<pre><code class="lang-js"><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> navigate = useNavigate();
</code></pre>
<p>Then call this function with an event handler, and pass in the home page route.</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { useEffect, useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { useURLID } <span class="hljs-keyword">from</span> <span class="hljs-string">"./useURLID"</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">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ProductItem</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> { id } = useURLID();
  <span class="hljs-keyword">const</span> [singleProduct, setSingleProduct] = useState({});
  <span class="hljs-keyword">const</span> [loading, setLoading] = useState(<span class="hljs-literal">false</span>);

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">fetchData</span>(<span class="hljs-params"></span>) </span>{
      setLoading(<span class="hljs-literal">true</span>);
      <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">`http://localhost:9000/products/<span class="hljs-subst">${id}</span>`</span>);

        <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> res.json();

        setSingleProduct(data);
      } <span class="hljs-keyword">catch</span> (error) {
        <span class="hljs-built_in">console</span>.log(error);
      } <span class="hljs-keyword">finally</span> {
        setLoading(<span class="hljs-literal">false</span>);
      }
    }
    fetchData();
  }, [id]);

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

  <span class="hljs-comment">// If loading, display the loading div</span>
  <span class="hljs-keyword">if</span> (loading) <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>Loading...<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>;

  <span class="hljs-comment">// If not loading, display the product details</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">"single__product"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>
       // Navigate to the home page
        <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> navigate("/")}&gt;🔙 <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>
          {singleProduct.itemName} Page id: {id}
        <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">section</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">figure</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"product__img-container"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">img</span>
            <span class="hljs-attr">className</span>=<span class="hljs-string">"product__img"</span>
            <span class="hljs-attr">src</span>=<span class="hljs-string">{singleProduct.imageUrl}</span>
            <span class="hljs-attr">alt</span>=<span class="hljs-string">"Image"</span>
          /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">figure</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">aside</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>{singleProduct.itemName}<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>{singleProduct.notes}<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">h4</span>&gt;</span>
            Category: <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>{singleProduct.type}<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">h4</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>
            Width: <span class="hljs-tag">&lt;<span class="hljs-name">strong</span>&gt;</span>{singleProduct?.size?.width}<span class="hljs-tag">&lt;/<span class="hljs-name">strong</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>
            Length: <span class="hljs-tag">&lt;<span class="hljs-name">strong</span>&gt;</span>{singleProduct?.size?.length}<span class="hljs-tag">&lt;/<span class="hljs-name">strong</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">aside</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">section</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<p>Testing your final result now gives the following:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/10/final-take-1.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Final take showing all features</em></p>
<h2 id="heading-real-world-examples">Real-World Examples</h2>
<ul>
<li><strong>E-commerce platforms</strong>: Think of sites like Amazon. They use URLs to let you share specific product searches or settings. Thanks to this, people can easily share their favourite items or shopping lists with friends.</li>
<li><strong>Data Tools</strong>: Tools like <a target="_blank" href="https://www.tableau.com/">Tableau</a> save your custom views in the URL. This means teams can share specific data pictures with each other, making talks, shows, and decisions faster and clearer.</li>
</ul>
<h3 id="heading-additional-information">Additional Information</h3>
<p>I’d like to point out a couple of things in the article not highlighted.</p>
<ul>
<li>The CSS used contains <a target="_blank" href="https://developer.chrome.com/articles/css-nesting/">native CSS nesting</a> that isn’t fully supported by all browsers, so if there are UI irregularities you notice, it may be from the browser you’re using. Feel free to switch to a browser like Google Chrome for better support or check for browser support with a tool like <a target="_blank" href="https://caniuse.com/">CanIUse</a> and add polyfills to your code.</li>
<li>If this article delved into things that were a tad complicated for you (how routing works), feel free to check out this article on <a target="_blank" href="https://www.freecodecamp.org/news/improve-user-experience-in-react-by-animating-routes-using-framer-motion/">Routing Animations</a> for a better understanding.</li>
<li>If you’re interested in the full code, here’s the repo, <a target="_blank" href="https://github.com/Daiveedjay/URL-State-Management">GitHub</a>, and the Live version is here. <a target="_blank" href="https://free-code-camp-url-state-manangement.netlify.app/">Demo</a></li>
<li>As an added feature, I made the code fully responsive for anyone interested in creating masonry grids for future projects, cheers!🍷</li>
</ul>
<h2 id="heading-conclusion">Conclusion</h2>
<p>React's state management has evolved, with URL-based state emerging as a standout. This method not only simplifies state management but also fosters collaboration and transparency between users and developers.</p>
<p>So, the next time you're online and think of sharing data via a URL, remember that you have the tools to implement this feature yourself 😉. It's a nudge for developers to explore the untapped potential of URLs in state management.</p>
<h3 id="heading-contact-information">Contact Information</h3>
<p>Want to connect or contact me? Feel free to hit me up on the following:</p>
<ul>
<li>Twitter / X: <a target="_blank" href="https://twitter.com/JajaDavid8">@jajadavid8</a></li>
<li>LinkedIn: <a target="_blank" href="https://www.linkedin.com/in/david-jaja-8084251b4/">David Jaja</a></li>
<li>Email: <a target="_blank" href="mailto:Jajadavidjid@gmail.com">Jajadavidjid@gmail.com</a></li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Set Up Social Media Web Authentication using Firebase ]]>
                </title>
                <description>
                    <![CDATA[ User authentication is extremely important in the context of web development. The way users log in affects their overall experience and engagement with an application. It also affects how they initially perceive it. Authentication techniques are cont... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/social-media-based-web-authentication-with-firebase/</link>
                <guid isPermaLink="false">66bb891dc32849d18c5cdca9</guid>
                
                    <category>
                        <![CDATA[ authentication ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Firebase ]]>
                    </category>
                
                    <category>
                        <![CDATA[ social media ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web App Security ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ David Jaja ]]>
                </dc:creator>
                <pubDate>Thu, 31 Aug 2023 00:12:32 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/08/Article-Cover--3.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>User authentication is extremely important in the context of web development. The way users log in affects their overall experience and engagement with an application. It also affects how they initially perceive it.</p>
<p>Authentication techniques are continually evolving as social media sites continue to grow in popularity. The ability to log into web apps using social network accounts is a helpful advance in this area.</p>
<p>This article discusses how you can enhance the user login process for web applications by employing social media authentication through Firebase. It goes into the benefits, setup methods, and integration approaches while offering helpful guidelines.</p>
<h2 id="heading-heres-what-well-cover">Here's what we'll cover:</h2>
<ol>
<li><a class="post-section-overview" href="#heading-why-use-social-media-authentication">Why Use Social Media Authentication?</a></li>
<li><a class="post-section-overview" href="#heading-prerequisites">Prerequisites</a></li>
<li><a class="post-section-overview" href="#heading-what-is-firebase-and-why-use-it-for-authentication">What is Firebase and Why Use it for Authentication?</a></li>
<li><a class="post-section-overview" href="#heading-how-to-set-up-firebase-for-social-media-authentication">How to Set Up Firebase for Social Media Authentication</a></li>
<li><a class="post-section-overview" href="#heading-how-to-set-up-your-react-app">How to Set Up Your React App</a></li>
<li><a class="post-section-overview" href="#heading-how-to-integrate-social-media-authentication-in-your-app">How to Integrate Social Media Authentication in Your App</a></li>
<li><a class="post-section-overview" href="#heading-striking-the-right-balance-offering-both-social-media-and-emailpassword-authentication">Offering Both Social Media and Email/Password Authentication</a></li>
<li><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></li>
</ol>
<h2 id="heading-why-use-social-media-authentication">Why Use Social Media Authentication?</h2>
<p>I'm sure you've grown weary of the usual username-password routine when logging into a new platform. It often entails creating a new password on the spot or resorting to insecure password conventions that could grant unauthorized access to your many accounts.</p>
<p>Fortunately, social media authentication offers some advantages:</p>
<ol>
<li>Effortless User Experience: Social media login choices simplify the registration process, making it convenient for users to initiate their app usage.</li>
<li>Heightened Security: Social media platforms implement strong security measures that can bolster the safety of your app's users.</li>
<li>Elimination of Password Hassles: Through social media authentication, users are relieved from the burden of remembering numerous passwords, reducing the inconvenience of managing credentials.</li>
<li>Reduced Account Abandonment: Social media login prompts users to join and interact with your app, minimizing the chances of them leaving the registration process unfinished.</li>
<li>Access to Trustworthy User Information: Social media platforms provide substantial user information, which can be harnessed to personalize the experience offered by your app.</li>
<li>Streamlined Account Recovery: In instances of forgotten passwords, social media authentication presents a straightforward approach for users to regain entry to their accounts.</li>
</ol>
<p>In summary, social media authentication offers a convenient and secure method for users to join and use your app. It leads to an improved user experience, and decreased account abandonment, and grants you access to valuable user insights.</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>This article is intended for those with a solid grasp of the following concepts:</p>
<ul>
<li>HTML, CSS, and JavaScript</li>
<li>React and React Routing</li>
<li>Fundamental familiarity with using Firebase</li>
</ul>
<h2 id="heading-what-is-firebase-and-why-use-it-for-authentication">What is Firebase and Why Use it for Authentication?</h2>
<p>Firebase serves as a comprehensive platform, providing developers with backend services and tools to create web and mobile applications. </p>
<p>One of its key offerings is an authentication service that streamlines the process of integrating authentication features into apps. </p>
<p>With <a target="_blank" href="https://firebase.google.com/">Firebase</a>, implementing authentication becomes more straightforward, thanks to its provision of pre-built user interface components, developer-friendly APIs, and support for various authentication methods.</p>
<h2 id="heading-how-to-set-up-firebase-for-social-media-authentication">How to Set Up Firebase for Social Media Authentication</h2>
<h3 id="heading-step-1-create-a-firebase-project">Step 1: Create a Firebase Project</h3>
<ol>
<li>Go to <a target="_blank" href="https://console.firebase.google.com/">the Firebase Console</a> and sign in with your Google account.</li>
<li>Click the "Add Project" button.</li>
<li>Enter a name for your project and select a location for your data storage.</li>
<li>Click the "Create" button.</li>
</ol>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/Screenshot-2023-08-22-082447.png" alt="Image" width="600" height="400" loading="lazy">
<em>Firebase console homepage</em></p>
<h3 id="heading-step-2-register-a-web-app">Step 2: Register a Web app</h3>
<p>This feature enables you to register your web applications to access the features of Firebase via web apps.</p>
<ol>
<li>In the Firebase Console, click the "Web" (&lt;/&gt;) icon.</li>
<li>Click the "Add App" button.</li>
<li>Enter a name for your app and select the "Web" app type.</li>
<li>Click the "Register" button.</li>
</ol>
<p>After you have created a Firebase project and registered a web app, you can start using Firebase for social media authentication.</p>
<h3 id="heading-step-3-discover-social-media-sign-in-methods">Step 3: Discover Social Media Sign-In Methods</h3>
<p>To do this, once your project is created, you'll need to navigate to the "Authentication" section on the left-hand menu.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/2-Auth-side-bar-shown.png" alt="Image" width="600" height="400" loading="lazy">
<em>Showing the Authentication sidebar</em></p>
<p>Under the "Sign-in method" tab, you'll find a list of authentication providers from which you can choose one:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/Screenshot-2023-08-22-082758.png" alt="Image" width="600" height="400" loading="lazy">
<em>Displaying various Authentication methods</em></p>
<h3 id="heading-step-4-configure-social-media-providers">Step 4: Configure Social Media Providers</h3>
<h4 id="heading-how-to-configure-google-auth">How to configure Google auth:</h4>
<p>To configure Google auth, simply add a support email, and you’re all set.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/google-enable.png" alt="Image" width="600" height="400" loading="lazy">
<em>Adding a support mail for google auth</em></p>
<h4 id="heading-how-to-configure-github-auth">How to configure GitHub auth:</h4>
<p>To configure GitHub auth, you'll need a Client ID and Client Secret. To get these, sign in to your <a target="_blank" href="https://github.com/">GitHub account</a> and go to Settings &gt; Developer settings.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/github--settings.png" alt="Image" width="600" height="400" loading="lazy">
<em>Github settings panel</em></p>
<p>Then, navigate to OAuth and create a new OAuth application.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/Setting-up-Github-OAuth.png" alt="Image" width="600" height="400" loading="lazy">
<em>Creating a github OAuth application</em></p>
<p>In order to get the Authorization callback, go back to your Firebase console and copy the URL in the GitHub setup.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/github-callback-url.png" alt="Image" width="600" height="400" loading="lazy">
<em>GitHub callback URL</em></p>
<p>Note: To complete this process, you’d need to have your app already hosted or at least a URL to where your app is going to be hosted.</p>
<p>Next, you’ll be routed to a page where your app has been registered and you have your Client ID and Secret.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/3-Github-Client-ID-and-Secret-generated.png" alt="Image" width="600" height="400" loading="lazy">
<em>GitHub Client ID and secret Generated</em></p>
<p>Copy those details and use them to register GitHub as an auth service on Firebase.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/4-Filling-in-github-details-in-fb.png" alt="Image" width="600" height="400" loading="lazy">
<em>Filling GitHub details on Firebase</em></p>
<h4 id="heading-how-to-configure-twitter-auth">How to configure Twitter auth:</h4>
<p>Similar to Github, start by logging into your Twitter developer account. If you don’t have one, sign up with the <a target="_blank" href="https://developer.twitter.com/en/portal/petition/essential/basic-info">Twitter Developer Portal</a>. It looks something like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/Twitter-Developers-signup.png" alt="Image" width="600" height="400" loading="lazy">
<em>Twitter Developer Signup</em></p>
<p>After filling in the details, you’ll be routed to the homepage.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/5-twitter-dev-homepage.png" alt="Image" width="600" height="400" loading="lazy">
<em>Twitter Dev homepage</em></p>
<p>Click on your default app, and set up user authentication.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/Twitter-user-auth-setup.png" alt="Image" width="600" height="400" loading="lazy">
<em>Twitter OAuth app setup</em></p>
<p>Don’t forget to get the callback URL from Firebase and set the Website URL to the URL where your app is hosted.</p>
<p>After setting it up, navigate to your project’s keys and tokens and generate new ones.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/Screenshot-2023-08-25-164558.png" alt="Image" width="600" height="400" loading="lazy">
<em>Generating new App Key and Secret</em></p>
<p>Paste those details back in Firebase to set up Twitter auth. </p>
<p>And with that, your three social media platforms have be set up for authentication.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/All-auths-setup.png" alt="Image" width="600" height="400" loading="lazy">
<em>All Auth's set up</em></p>
<h2 id="heading-ia"> </h2>
<p>How to Set Up Your React App</p>
<p>Now we need to get your React app set up. You'll start by creating a new React app using <a target="_blank" href="https://vitejs.dev/guide/">Vite</a>.</p>
<p>Create a folder on your computer and open that folder with your preferred IDE. Open that IDE’s terminal and run this command:</p>
<pre><code class="lang-bash">npm create vite@latest
</code></pre>
<p>When the details load, select React and wait for the installation to complete.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/Vite-React.png" alt="Image" width="600" height="400" loading="lazy">
<em>Creating a React App with Vite</em></p>
<p>You’ll be left with a handful of files and some boilerplate code that you can get rid of.</p>
<p>Next, run <code>npm run dev</code> in the terminal to start a development server on port <code>http://localhost:5173/</code>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/Vit-setup.png" alt="Image" width="600" height="400" loading="lazy">
<em>React app running in browser</em></p>
<p>To use Firebase in your app, you must first define a Firebase config file. This file contains all the necessary data used to identify your Firebase app.</p>
<p>So create a folder in your <code>src</code> directory called <code>firebase</code>. Then nest a <code>config.js</code> file in that folder and paste the config file details from your Firebase console you saved earlier.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/6-firebase-config-in-vscode.png" alt="Image" width="600" height="400" loading="lazy">
<em>Firebase config details</em></p>
<p>Finally, install Firebase via your terminal to use its services in your app.</p>
<pre><code class="lang-bash">npm i firebase
</code></pre>
<h2 id="heading-how-to-integrate-social-media-authentication-in-your-app">How to Integrate Social Media Authentication in Your App</h2>
<p>Considering how large this section would be, it’ll be divided into several sub-sections.</p>
<ol>
<li>Setting up the UI logic for authentication</li>
<li>Setting up the Authentication logic</li>
<li>Implementing Global Authentication State</li>
<li>Creating a custom hook for Social Media Authentication</li>
<li>Creating Routes and Implementing Routing</li>
<li>Social Media Authentication</li>
<li>Route Guarding via the User State</li>
<li>Creating a useLogout hook</li>
<li>Testing the logout functionality</li>
</ol>
<h3 id="heading-how-to-set-up-the-ui-logic-for-authentication">How to set up the UI logic for authentication</h3>
<p>Create a folder (pages) in the <code>src</code> directory that houses the pages you want in your application.</p>
<p>For this implementation, there will be 2 files in the pages folder, <code>Auth.jsx</code> and <code>Home.jsx</code>. These files will act as the pages the user can see either when authenticated or not.</p>
<h3 id="heading-how-to-set-up-the-authentication-logic">How to set up the authentication logic</h3>
<p>Start by importing and initializing Firebase auth, as well as the social media platforms enabled on Firebase in your config.</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> {
  getAuth,
  GoogleAuthProvider,
  GithubAuthProvider,
  TwitterAuthProvider,
} <span class="hljs-keyword">from</span> <span class="hljs-string">"firebase/auth"</span>;

<span class="hljs-comment">// Initialize Firebase</span>
<span class="hljs-keyword">const</span> app = initializeApp(firebaseConfig);
<span class="hljs-keyword">const</span> auth = getAuth(app);

<span class="hljs-keyword">const</span> googleProvider = <span class="hljs-keyword">new</span> GoogleAuthProvider();
<span class="hljs-keyword">const</span> githubProvider = <span class="hljs-keyword">new</span> GithubAuthProvider();
<span class="hljs-keyword">const</span> twitterProvider = <span class="hljs-keyword">new</span> TwitterAuthProvider();
</code></pre>
<p>Then export these initialized functions to use them in other parts of your application.</p>
<pre><code class="lang-js"><span class="hljs-keyword">export</span> { auth, googleProvider, githubProvider, twitterProvider };
</code></pre>
<h3 id="heading-how-to-implement-global-authentication-state">How to implement Global Authentication State</h3>
<p>To ensure a consistent authentication state throughout your application, consider using the React Context approach.</p>
<h4 id="heading-step-1-create-an-authcontext">Step 1: Create an AuthContext</h4>
<p>Start by generating a context folder within your src directory and then create an <code>AuthContext.jsx</code> file within it. In the <code>AuthContext</code> file, import essential hooks from React and Firebase.</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { createContext, useReducer, useEffect, useContext } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { auth } <span class="hljs-keyword">from</span> <span class="hljs-string">"../firebase/config"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> AuthContext = createContext();
</code></pre>
<h4 id="heading-step-2-define-a-reducer-function">Step 2: Define a reducer function</h4>
<p>Construct a reducer function to manage state changes for authentication-related actions using the following code:</p>
<pre><code class="lang-js"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> authReducer = <span class="hljs-function">(<span class="hljs-params">state, action</span>) =&gt;</span> {
  <span class="hljs-keyword">switch</span> (action.type) {
    <span class="hljs-comment">// When the action type is "LOGIN", update the state with the new user information</span>
    <span class="hljs-keyword">case</span> <span class="hljs-string">"LOGIN"</span>:
      <span class="hljs-keyword">return</span> { ...state, <span class="hljs-attr">user</span>: action.payload };

    <span class="hljs-comment">// When the action type is "LOGOUT", update the state to remove the user information</span>
    <span class="hljs-keyword">case</span> <span class="hljs-string">"LOGOUT"</span>:
      <span class="hljs-keyword">return</span> { ...state, <span class="hljs-attr">user</span>: <span class="hljs-literal">null</span> };

    <span class="hljs-comment">// When the action type is "AUTH_IS_READY", update the state with user information and</span>
    <span class="hljs-comment">// set a state to indicate that the authentication process is complete</span>
    <span class="hljs-keyword">case</span> <span class="hljs-string">"AUTH_IS_READY"</span>:
      <span class="hljs-keyword">return</span> { <span class="hljs-attr">user</span>: action.payload, <span class="hljs-attr">authIsReady</span>: <span class="hljs-literal">true</span> };

    <span class="hljs-comment">// For any other action type, return the current state without any changes</span>
    <span class="hljs-keyword">default</span>:
      <span class="hljs-keyword">return</span> state;
  }
};
</code></pre>
<h4 id="heading-step-3-create-authcontextprovider-component">Step 3: Create AuthContextProvider Component</h4>
<p>Create a provider component that wraps your entire App component, using the reducer for authentication state management.</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { useEffect, useReducer } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { onAuthStateChanged } <span class="hljs-keyword">from</span> <span class="hljs-string">"firebase/auth"</span>; 


<span class="hljs-comment">// Authentication context provider component</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> AuthContextProvider = <span class="hljs-function">(<span class="hljs-params">{ children }</span>) =&gt;</span> {
  <span class="hljs-comment">// Initialize authentication state using a reducer</span>
  <span class="hljs-keyword">const</span> [state, dispatch] = useReducer(authReducer, {
    <span class="hljs-attr">user</span>: <span class="hljs-literal">null</span>,
    <span class="hljs-attr">authIsReady</span>: <span class="hljs-literal">false</span>,
  });

  <span class="hljs-comment">// Effect to determine initial authentication state and update context</span>
  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-comment">// Subscribe to authentication state changes</span>
    <span class="hljs-keyword">const</span> unsub = onAuthStateChanged(auth, <span class="hljs-function">(<span class="hljs-params">user</span>) =&gt;</span> {
      <span class="hljs-comment">// Dispatch an action to update the state with the user information</span>
      dispatch({ <span class="hljs-attr">type</span>: <span class="hljs-string">"AUTH_IS_READY"</span>, <span class="hljs-attr">payload</span>: user });

      <span class="hljs-comment">// Unsubscribe to avoid further unnecessary updates</span>
      unsub(); <span class="hljs-comment">// Unsubscribe once the initial auth state is determined</span>
    });
  }, []);

  <span class="hljs-comment">// Provide authentication state and dispatch function to children components</span>
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">AuthContext.Provider</span> <span class="hljs-attr">value</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">...state</span>, <span class="hljs-attr">dispatch</span> }}&gt;</span>
      {children}
    <span class="hljs-tag">&lt;/<span class="hljs-name">AuthContext.Provider</span>&gt;</span></span>
  );
};
</code></pre>
<h4 id="heading-step-4-implement-useauthcontext-custom-hook">Step 4: Implement useAuthContext custom hook</h4>
<p>You can simplify access to the authentication context with a custom hook, like this:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { useContext } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-comment">// Custom hook to access the authentication context</span>
<span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">useAuthContext</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-comment">// Get the authentication context from the nearest AuthContextProvider</span>
  <span class="hljs-keyword">const</span> context = useContext(AuthContext);

  <span class="hljs-comment">// Check if the context was successfully obtained</span>
  <span class="hljs-keyword">if</span> (!context) {
    <span class="hljs-keyword">throw</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">"useAuthContext must be used inside an AuthContextProvider"</span>);
  }

  <span class="hljs-comment">// Return the authentication context object for use in components</span>
  <span class="hljs-keyword">return</span> context;
}
</code></pre>
<h4 id="heading-how-to-integrating-the-authcontextprovider">How to integrating the AuthContextProvider</h4>
<p>Finally, integrate the <code>AuthContextProvider</code> into your main application setup</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> ReactDOM <span class="hljs-keyword">from</span> <span class="hljs-string">"react-dom/client"</span>;
<span class="hljs-keyword">import</span> App <span class="hljs-keyword">from</span> <span class="hljs-string">"./App.jsx"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"./index.css"</span>;
<span class="hljs-keyword">import</span> { AuthContextProvider } <span class="hljs-keyword">from</span> <span class="hljs-string">"./context/AuthContext.jsx"</span>;

ReactDOM.createRoot(<span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"root"</span>)).render(
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">React.StrictMode</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">AuthContextProvider</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">App</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">AuthContextProvider</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">React.StrictMode</span>&gt;</span></span>
);
</code></pre>
<p>With that, all parts of your app can access the context values from the <code>AuthContext</code>.</p>
<h3 id="heading-how-to-create-a-custom-hook-for-social-media-authentication">How to create a custom hook for Social Media Authentication</h3>
<p>Firebase authentication processes are similar in pattern and code structure. So it's a good idea to follow the DRY principle and create a utility hook that performs authentication for all social media platforms. This allows you to reuse the same code for each platform, making your code more efficient and easier to maintain.</p>
<p>Here is the step-by-step process to follow to create a custom hook for social media authentication.</p>
<h4 id="heading-step-1-create-the-custom-hook">Step 1: Create the custom hook</h4>
<p>In your source directory, establish a hooks folder and within it, create a file named <code>useSocialSignup.jsx</code>.</p>
<h4 id="heading-step-2-import-dependencies">Step 2: Import dependencies</h4>
<p>Import the necessary functions from React and Firebase into your <code>useSocialSignup</code> file.</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { useEffect, useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { signInWithPopup } <span class="hljs-keyword">from</span> <span class="hljs-string">"firebase/auth"</span>;
<span class="hljs-keyword">import</span> { auth } <span class="hljs-keyword">from</span> <span class="hljs-string">"../firebase/config"</span>;
<span class="hljs-keyword">import</span> { useAuthContext } <span class="hljs-keyword">from</span> <span class="hljs-string">"../context/AuthContext"</span>;
</code></pre>
<h4 id="heading-step-3-define-the-hook-function">Step 3: Define the hook function</h4>
<p>Develop the <code>useSocialSignup</code> function, which takes a provider as a parameter and returns an object containing an error state, pending state, and the sign-in function for the social provider.</p>
<pre><code class="lang-js"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> useSocialSignup = <span class="hljs-function">(<span class="hljs-params">provider</span>) =&gt;</span> {
  <span class="hljs-comment">// State variables to manage sign-up process</span>
  <span class="hljs-keyword">const</span> [error, setError] = useState(<span class="hljs-literal">null</span>);
  <span class="hljs-keyword">const</span> [isPending, setIsPending] = useState(<span class="hljs-literal">false</span>);
  <span class="hljs-keyword">const</span> [isCancelled, setIsCancelled] = useState(<span class="hljs-literal">false</span>);

  <span class="hljs-comment">// Accessing the authentication context's dispatch function</span>
  <span class="hljs-keyword">const</span> { dispatch } = useAuthContext();

  <span class="hljs-comment">// Function to initiate the social sign-up process</span>
  <span class="hljs-keyword">const</span> signInWithSocial = <span class="hljs-keyword">async</span> () =&gt; {
    setError(<span class="hljs-literal">null</span>);
    setIsPending(<span class="hljs-literal">true</span>);

    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> signInWithPopup(auth, provider);

      dispatch({ <span class="hljs-attr">type</span>: <span class="hljs-string">"LOGIN"</span>, <span class="hljs-attr">payload</span>: res.user });

      <span class="hljs-keyword">if</span> (!isCancelled) {
        setIsPending(<span class="hljs-literal">false</span>);
        setError(<span class="hljs-literal">null</span>);
      }
    } <span class="hljs-keyword">catch</span> (err) {
      setError(err.message);
      setIsPending(<span class="hljs-literal">false</span>);
    }
  };

  <span class="hljs-comment">// Effect hook to set isCancelled to true when component unmounts</span>
  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-function">() =&gt;</span> setIsCancelled(<span class="hljs-literal">true</span>);
  }, []);

  <span class="hljs-comment">// Return values and functions for component usage</span>
  <span class="hljs-keyword">return</span> { error, isPending, signInWithSocial };
};
</code></pre>
<p>This hook encapsulates the process of signing in with social providers. It manages error, pending, and cancellation states, interacts with Firebase authentication, and utilizes the authentication context to dispatch actions.</p>
<h3 id="heading-how-to-create-routes-and-implementing-routing">How to create routes and implementing routing</h3>
<p>To ensure smooth navigation and user experience, setting up routes becomes crucial after implementing authentication logic. These well-organized steps guide you through the process.</p>
<h4 id="heading-step-1-install-react-router-dom">Step 1: Install react-router-dom</h4>
<p>Install <a target="_blank" href="https://www.npmjs.com/package/react-router-dom">the react-router-dom package</a>, a popular choice for managing routing in React applications.</p>
<pre><code class="lang-bash">npm i react-router-dom
</code></pre>
<h4 id="heading-step-2-import-dependencies-1">Step 2: Import dependencies</h4>
<p>In your <code>App.jsx</code> file, import necessary components and functions for routing.</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { BrowserRouter, Navigate, Route, Routes } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-router-dom"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"./App.css"</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> Auth <span class="hljs-keyword">from</span> <span class="hljs-string">"./pages/Auth"</span>;
</code></pre>
<h4 id="heading-step-3-define-routes">Step 3: Define routes</h4>
<p>Wrap your application content in a BrowserRouter component and use the Routes component to define your routes. Utilize the Route component to map each route path to its corresponding component.</p>
<pre><code class="lang-js"><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">BrowserRouter</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">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"/auth"</span> <span class="hljs-attr">element</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">Auth</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">BrowserRouter</span>&gt;</span></span>
  );
}
</code></pre>
<p>At the moment, you can freely navigate between routes, like so:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/Onauth-routing.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Moving between Routes without Auth</em></p>
<h3 id="heading-social-media-authentication">Social Media Authentication</h3>
<p>To ensure your efforts haven't been in vain, head over to the <code>Auth.jsx</code> to implement authentication.</p>
<h4 id="heading-step-1-import-dependencies">Step 1: Import dependencies</h4>
<p>In your <code>Auth.jsx</code> file, start by importing necessary providers, context, and the custom signup hook.</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> {
  googleProvider,
  twitterProvider,
  githubProvider,
} <span class="hljs-keyword">from</span> <span class="hljs-string">"../firebase/config"</span>;
<span class="hljs-keyword">import</span> { useSocialSignup } <span class="hljs-keyword">from</span> <span class="hljs-string">"../hooks/useSocialSignup"</span>;
<span class="hljs-keyword">import</span> {useEffect} <span class="hljs-keyword">from</span> ‘react’

<span class="hljs-keyword">import</span> {useAuthContext} <span class="hljs-keyword">from</span> “../context/AuthContext”
</code></pre>
<h4 id="heading-step-2-create-instances-of-the-hook">Step 2: Create instances of the hook</h4>
<p>Create instances of the <code>useSocialSignup</code> custom hook for each authentication provider.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> google = useSocialSignup(googleProvider);
<span class="hljs-keyword">const</span> twitter = useSocialSignup(twitterProvider);
<span class="hljs-keyword">const</span> github = useSocialSignup(githubProvider);
</code></pre>
<h4 id="heading-step-3-add-buttons-for-social-sign-up">Step 3: Add buttons for social sign-up</h4>
<p>Create buttons for each social sign-up option (Google, Twitter, GitHub) and attach onClick event handlers to call the <code>signInWithSocial</code> function from the respective hook.</p>
<pre><code class="lang-js"><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">"utility__page"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Welcome to my Auth Page<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{google.signInWithSocial}</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{GoogleIcon}</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>Google<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{twitter.signInWithSocial}</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{TwitterIcon}</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>Twitter<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{github.signInWithSocial}</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{GithubIcon}</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>GitHub<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
    <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>
);
</code></pre>
<h4 id="heading-step-4-apply-styling">Step 4: Apply styling</h4>
<p>You can use the provided CSS below to style your components for a clean and organized appearance.</p>
<pre><code class="lang-css">* {
  <span class="hljs-attribute">box-sizing</span>: border-box;
  <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-selector-tag">html</span> {
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">62.5%</span>;
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#121212</span>;
}

<span class="hljs-selector-class">.utility__page</span> {
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">100vh</span>;
  <span class="hljs-attribute">justify-content</span>: center;
  <span class="hljs-attribute">align-items</span>: center;
  <span class="hljs-attribute">font-family</span>: <span class="hljs-string">"Segoe UI"</span>, Tahoma, Geneva, Verdana, sans-serif;
  <span class="hljs-attribute">row-gap</span>: <span class="hljs-number">2rem</span>;
  <span class="hljs-attribute">flex-direction</span>: column;
  <span class="hljs-attribute">background</span>: <span class="hljs-number">#e2dbd9</span>;
}

<span class="hljs-selector-tag">h1</span> {
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">5rem</span>;
}

<span class="hljs-selector-tag">button</span> {
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">1rem</span> <span class="hljs-number">4rem</span>;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">2rem</span>;
  <span class="hljs-attribute">border</span>: none;
  <span class="hljs-attribute">cursor</span>: pointer;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">5px</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">gap</span>: <span class="hljs-number">1rem</span>;
}

<span class="hljs-selector-tag">button</span> <span class="hljs-selector-tag">img</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">20px</span>;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">20px</span>;
}

<span class="hljs-selector-class">.user</span> {
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">3rem</span>;
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">align-items</span>: center;
  <span class="hljs-attribute">column-gap</span>: <span class="hljs-number">1rem</span>;
}

<span class="hljs-selector-class">.logout</span> {
  <span class="hljs-attribute">background</span>: <span class="hljs-built_in">rgb</span>(<span class="hljs-number">208</span>, <span class="hljs-number">84</span>, <span class="hljs-number">84</span>);
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#fff</span>;
}

<span class="hljs-selector-class">.profile_img</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">5rem</span>;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">5rem</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">50%</span>;
}
</code></pre>
<p>At the moment, your auth page looks something like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/Auth-page.png" alt="Image" width="600" height="400" loading="lazy">
<em>Auth page after applying styling</em></p>
<h4 id="heading-step-5-test-the-authentication">Step 5: Test the authentication</h4>
<p>To test authentication, import the user from your <code>AuthContext</code> and log it to the console using a <code>useEffect</code>.</p>
<pre><code class="lang-js">  <span class="hljs-keyword">const</span> { user } = useAuthContext();
  useEffect(<span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">console</span>.log(user), [user]);
</code></pre>
<p>Testing the auth now gives the following:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/first-login-giffy.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Authentication confirmed in the console via the user object</em></p>
<p>As you can see, you’ve successfully logged a user in using Social Media Authentication. Kudos!</p>
<p>To confirm, head over to your Firebase auth page and check for valid users.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/Valid-users-check.png" alt="Image" width="600" height="400" loading="lazy">
<em>Confirming signed up user on Firebase</em></p>
<p>Feel free to try other login methods as they all work the same.</p>
<h3 id="heading-route-gaurding-via-the-user-state">Route Gaurding via the User State</h3>
<p>To prevent unauthorized access, set up route guards that check the user's authentication state in your <code>App.jsx</code> file.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> { user, authIsReady } = useAuthContext();

<span class="hljs-keyword">if</span> (!authIsReady) {
  <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>; <span class="hljs-comment">// Return null while waiting for authIsReady</span>
}

<span class="hljs-keyword">return</span> (
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">BrowserRouter</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">Routes</span>&gt;</span>
      {user ? (
        <span class="hljs-tag">&lt;&gt;</span>
          {/* Authenticated routes */}
          <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;
          {/* Route guards */}
          <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">Navigate</span> <span class="hljs-attr">to</span>=<span class="hljs-string">"/"</span> /&gt;</span>} /&gt;
        <span class="hljs-tag">&lt;/&gt;</span>
      ) : (
        <span class="hljs-tag">&lt;&gt;</span>
          {/* Authentication routes */}
          <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"/auth"</span> <span class="hljs-attr">element</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">Auth</span> /&gt;</span>} /&gt;
          {/* Route guards */}
          <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">Navigate</span> <span class="hljs-attr">to</span>=<span class="hljs-string">"/auth"</span> /&gt;</span>} /&gt;
        <span class="hljs-tag">&lt;/&gt;</span></span>
      )}
    &lt;/Routes&gt;
  &lt;/BrowserRouter&gt;
);
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/plain-home-page-after-auth.png" alt="Image" width="600" height="400" loading="lazy">
<em>Routed to home page after adding route guards</em></p>
<p>As you can see, you’ve been routed to the home page, and even if you attempt to go the auth page, you’d be routed back here.</p>
<h4 id="heading-how-to-customize-the-home-page">How to customize the home page</h4>
<p>For the home page, fetch the user's details and display them if a user is authenticated.</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { useAuthContext } <span class="hljs-keyword">from</span> <span class="hljs-string">"../context/AuthContext"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Home</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> { user } = useAuthContext();
  <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">"utility__page "</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span> Home Page<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      {user &amp;&amp; (
        <span class="hljs-tag">&lt;&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"user"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span> You<span class="hljs-symbol">&amp;apos;</span>re logged in as: <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>

            <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>{user.displayName} <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"profile_img"</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{user.photoURL}</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</span>/&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
         <span class="hljs-tag">&lt;/&gt;</span></span>
      )}
    &lt;/div&gt;
  );
}
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/Auth-showing-details.png" alt="Image" width="600" height="400" loading="lazy">
<em>Home page showing custom user details</em></p>
<p>And voilà! You’ve been able to fetch some details about that user based on the info on the social media they used to log in.</p>
<h3 id="heading-how-to-create-a-uselogout-hook">How to create a useLogout hook</h3>
<p>The final step to complete your authentication process is to provide users with the ability to log out of your application. Here's how to create a useLogout hook:</p>
<h4 id="heading-step-1-create-the-hook">Step 1: Create the hook</h4>
<p>Create a new file called useLogout.jsx in your hooks folder. Import the necessary hooks and functions.</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { useEffect, useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { auth } <span class="hljs-keyword">from</span> <span class="hljs-string">"../firebase/config"</span>;
<span class="hljs-keyword">import</span> { signOut } <span class="hljs-keyword">from</span> <span class="hljs-string">"firebase/auth"</span>;
<span class="hljs-keyword">import</span> { useAuthContext } <span class="hljs-keyword">from</span> <span class="hljs-string">"../context/AuthContext"</span>;
</code></pre>
<h4 id="heading-step-2-create-the-hook-states">Step 2: Create the hook states</h4>
<p>Create states to manage the logout process, including error, pending, and cancellation states.</p>
<pre><code class="lang-js"><span class="hljs-comment">// Error state for potential errors during logout </span>
<span class="hljs-keyword">const</span> [error, setError] = useState(<span class="hljs-literal">null</span>); 
<span class="hljs-comment">// State to indicate if logout is in progress </span>
<span class="hljs-keyword">const</span> [isPending, setIsPending] = useState(<span class="hljs-literal">false</span>); 
<span class="hljs-comment">// State to track if the operation is cancelled</span>
<span class="hljs-keyword">const</span> [isCancelled, setIsCancelled] = useState(<span class="hljs-literal">false</span>);
</code></pre>
<h4 id="heading-step-3-extract-the-dispatch-function-from-the-authentication-context">Step 3: Extract the dispatch function from the authentication context</h4>
<p>This function will be used to indicate a logout action has been called:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> { dispatch } = useAuthContext();
</code></pre>
<h4 id="heading-step-4-create-the-hook-logic">Step 4: Create the hook logic</h4>
<p>Use a try-catch block create the logic of logging a user out:</p>
<pre><code class="lang-js"><span class="hljs-keyword">try</span> { 
<span class="hljs-comment">// Initiating the logout using Firebase's signOut function </span>
    <span class="hljs-keyword">await</span> signOut(auth); 
    dispatch({ <span class="hljs-attr">type</span>: <span class="hljs-string">"LOGOUT"</span> }); <span class="hljs-comment">// Dispatching a LOGOUT action </span>
<span class="hljs-comment">// If the operation wasn't cancelled, reset pending state and error </span>
   <span class="hljs-keyword">if</span> (!isCancelled) { 
       setIsPending(<span class="hljs-literal">false</span>); <span class="hljs-comment">// Resetting isPending after the asynchronous call completes </span>
       setError(<span class="hljs-literal">null</span>); <span class="hljs-comment">// Clearing any error that might have occurred </span>
     } 
   } <span class="hljs-keyword">catch</span> (err) { 
      <span class="hljs-comment">// Handling logout error </span>
     <span class="hljs-keyword">if</span> (!isCancelled) { 
        <span class="hljs-built_in">console</span>.log(err.message); <span class="hljs-comment">// Logging the error message</span>
        setError(err.message); <span class="hljs-comment">// Setting the error state in case of an error </span>
        setIsPending(<span class="hljs-literal">false</span>); <span class="hljs-comment">// Resetting pending state if an error occurs </span>
   } 
}
</code></pre>
<h4 id="heading-step-5-how-to-handle-unmounting">Step 5: How to handle unmounting</h4>
<p>In the case where the component is unmounted (the page closes or there’s a route change), you’ll want to handle that occurrence to prevent errors.</p>
<pre><code class="lang-js"><span class="hljs-comment">// Effect hook to set isCancelled to true when component unmounts</span>
   useEffect(<span class="hljs-function">() =&gt;</span> { 
       <span class="hljs-keyword">return</span> <span class="hljs-function">() =&gt;</span> setIsCancelled(<span class="hljs-literal">true</span>); <span class="hljs-comment">// The cleanup function runs when the component unmounts }, []);</span>
</code></pre>
<h4 id="heading-step-5-exporting-values">Step 5: Exporting values</h4>
<p>Return the relevant values and functions for other components to use.</p>
<pre><code class="lang-js"> <span class="hljs-keyword">return</span> { logout, error, isPending };
</code></pre>
<p>For ease of accesibility, here’s the full useLogout hook.</p>
<pre><code class="lang-js"><span class="hljs-comment">// Importing necessary hooks and functions</span>
<span class="hljs-keyword">import</span> { useEffect, useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { auth } <span class="hljs-keyword">from</span> <span class="hljs-string">"../firebase/config"</span>; <span class="hljs-comment">// Importing Firebase auth instance</span>
<span class="hljs-keyword">import</span> { signOut } <span class="hljs-keyword">from</span> <span class="hljs-string">"firebase/auth"</span>; <span class="hljs-comment">// Importing signOut function from Firebase</span>
<span class="hljs-keyword">import</span> { useAuthContext } <span class="hljs-keyword">from</span> <span class="hljs-string">"../context/AuthContext"</span>; <span class="hljs-comment">// Importing the custom hook to access the authentication context</span>

<span class="hljs-comment">// Custom hook for handling user logout</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> useLogout = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-comment">// State variables to manage logout process</span>
  <span class="hljs-keyword">const</span> [error, setError] = useState(<span class="hljs-literal">null</span>); <span class="hljs-comment">// Error state for potential errors during logout</span>
  <span class="hljs-keyword">const</span> [isPending, setIsPending] = useState(<span class="hljs-literal">false</span>); <span class="hljs-comment">// State to indicate if logout is in progress</span>
  <span class="hljs-keyword">const</span> [isCancelled, setIsCancelled] = useState(<span class="hljs-literal">false</span>); <span class="hljs-comment">// State to track if the operation is cancelled</span>
  <span class="hljs-keyword">const</span> { dispatch } = useAuthContext(); <span class="hljs-comment">// Accessing the authentication context's dispatch function</span>

  <span class="hljs-comment">// Function to initiate the logout process</span>
  <span class="hljs-keyword">const</span> logout = <span class="hljs-keyword">async</span> () =&gt; {
    setError(<span class="hljs-literal">null</span>); <span class="hljs-comment">// Clearing any previous errors</span>
    setIsPending(<span class="hljs-literal">true</span>); <span class="hljs-comment">// Indicating that the logout process is in progress</span>

    <span class="hljs-keyword">try</span> {
      <span class="hljs-comment">// Initiating the logout using Firebase's signOut function</span>
      <span class="hljs-keyword">await</span> signOut(auth);
      dispatch({ <span class="hljs-attr">type</span>: <span class="hljs-string">"LOGOUT"</span> }); <span class="hljs-comment">// Dispatching a LOGOUT action</span>

      <span class="hljs-comment">// If the operation wasn't cancelled, reset pending state and error</span>
      <span class="hljs-keyword">if</span> (!isCancelled) {
        setIsPending(<span class="hljs-literal">false</span>); <span class="hljs-comment">// Resetting isPending after the asynchronous call completes</span>
        setError(<span class="hljs-literal">null</span>); <span class="hljs-comment">// Clearing any error that might have occurred</span>
      }
    } <span class="hljs-keyword">catch</span> (err) {
      <span class="hljs-comment">// Handling logout error</span>
      <span class="hljs-keyword">if</span> (!isCancelled) {
        <span class="hljs-built_in">console</span>.log(err.message); <span class="hljs-comment">// Logging the error message</span>
        setError(err.message); <span class="hljs-comment">// Setting the error state in case of an error</span>
        setIsPending(<span class="hljs-literal">false</span>); <span class="hljs-comment">// Resetting pending state if an error occurs</span>
      }
    }
  };

  <span class="hljs-comment">// Effect hook to set isCancelled to true when component unmounts</span>
  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-function">() =&gt;</span> setIsCancelled(<span class="hljs-literal">true</span>); <span class="hljs-comment">// The cleanup function runs when the component unmounts</span>
  }, []);

  <span class="hljs-comment">// Returning the relevant values and functions for component usage</span>
  <span class="hljs-keyword">return</span> { logout, error, isPending };
};
</code></pre>
<h3 id="heading-how-to-test-the-logout-functionality">How to test the logout functionality</h3>
<p>In your Home.jsx component, import the useLogout hook and extract the logout function. Attach the logout function to a button's <code>onClick</code> event to enable users to log out.</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { useLogout } <span class="hljs-keyword">from</span> <span class="hljs-string">"../hooks/useLogout"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Home</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> { user } = useAuthContext();
  <span class="hljs-keyword">const</span> { logout } = useLogout(); <span class="hljs-comment">//logout function extracted</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">"utility__page "</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span> Home Page<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      {user &amp;&amp; (
        <span class="hljs-tag">&lt;&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"user"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span> You<span class="hljs-symbol">&amp;apos;</span>re logged in as: <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>{user.displayName} <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"profile_img"</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{user.photoURL}</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</span> /&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
           //logout function used
          <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"logout"</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{logout}</span>&gt;</span>
             Log out
          <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;/&gt;</span></span>
      )}
    &lt;/div&gt;
  );
}
</code></pre>
<p>At the moment, your home page looks like this;</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/before-logout.png" alt="Image" width="600" height="400" loading="lazy">
<em>Home page before logging the user out</em></p>
<p>Click on the button and log out the user.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/login-out-and-in.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Testing the log in and log out functionality</em></p>
<p>With that, your authentication process is completely set up, congrats!</p>
<h2 id="heading-striking-the-right-balance-offering-both-social-media-and-emailpassword-authentication">Striking the Right Balance: Offering Both Social Media and Email/Password Authentication</h2>
<p>User authentication is a key part of the user experience on any web app. Social media authentication can offer a streamlined experience and enhanced security, but it's important to strike a balance by also offering the option for email/password authentication. This ensures inclusivity, caters to various user preferences, and addresses privacy concerns. </p>
<p>By offering both options, you create a versatile and user-centric authentication process that contributes to a positive user experience.</p>
<p>An example of an ideal authentication page can be seen below.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/Final-signup-page.png" alt="Image" width="600" height="400" loading="lazy">
<em>Standard Auth Page</em></p>
<h2 id="heading-guidelines-for-building-auth-pages">Guidelines for Building Auth Pages</h2>
<p>It is important to apply some basics best practices when building authentication pages, such as:</p>
<ol>
<li>Showing all the possible ways a user can get authenticated in a clear and concise manner.</li>
<li>Using authentic company icons to build trust. You can find free company SVGs on sites like <a target="_blank" href="https://fontawesome.com/">Font Awesome</a>, <a target="_blank" href="https://fonts.google.com/icons">Google icons</a>, and so on.</li>
<li>Use intuitive icons to label inputs such as envelope for mail and padlock for password.</li>
<li>Address privacy concerns by clearly communicating how user data will be used and protected during the authentication process.</li>
</ol>
<p>For ease of accessibility, here’s a link to the <a target="_blank" href="https://github.com/Daiveedjay/OAuth-Article">repo</a>.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In conclusion, using social media login with Firebase is a smart strategy. It brings together user-friendliness, safety, and privacy. </p>
<p>By offering various ways to log in, websites can accommodate different user choices, be more inclusive, and adapt to new trends. </p>
<p>Balancing authentication options like this makes users happy and builds trust. This is important for creating modern websites and ensuring smooth, user-focused logins.</p>
<h3 id="heading-contact-information">Contact Information</h3>
<p>Want to connect or contact me? Feel free to hit me up on the following:</p>
<ul>
<li>Twitter / X : <a target="_blank" href="https://twitter.com/JajaDavid8">@jajadavid8</a></li>
<li>LinkedIn: <a target="_blank" href="https://www.linkedin.com/in/david-jaja-8084251b4/">David Jaja</a></li>
<li>Email: Jajadavidjid@gmail.com</li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Routing in Next.js – How to Use App Router in your Next Apps ]]>
                </title>
                <description>
                    <![CDATA[ In the ever-evolving world of web development, Next.js has consistently been a beacon of hope for developers seeking a balance between performance and ease of use.  With the introduction of the App Router in 2023, the framework has once again stirred... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/routing-in-nextjs/</link>
                <guid isPermaLink="false">66bb891a6b3bd8d6bf25ae3d</guid>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Next.js ]]>
                    </category>
                
                    <category>
                        <![CDATA[ routing ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ David Jaja ]]>
                </dc:creator>
                <pubDate>Thu, 24 Aug 2023 15:13:32 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/08/Article-Cover.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In the ever-evolving world of web development, Next.js has consistently been a beacon of hope for developers seeking a balance between performance and ease of use. </p>
<p>With the introduction of the App Router in 2023, the framework has once again stirred the pot, leaving many of us scratching our heads and pondering, "Do we stick with the tried-and-true Pages directory or embrace the shiny new App Router?". </p>
<p>In this exploration, we will delve into the unique facets of the App Router, offering valuable guidance for navigating these new features.</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<ul>
<li>A good understanding of JavaScript.</li>
<li>A good understanding of React.js and Next.js.</li>
</ul>
<h2 id="heading-a-brief-look-at-routing">A Brief Look at Routing</h2>
<p>Routing is a critical aspect of web apps that enables users to move between various pages. It guarantees that users can access different parts of an application, whether they are moving from a homepage to a product listing or navigating within single-page applications. </p>
<p>The Pages Directory and App Router are two crucial components that determine how users navigate through a Next.js application.</p>
<h2 id="heading-how-the-pages-directory-works-in-nextjs">How the Pages Directory Works in Next.js</h2>
<p>While the spotlight shines on the new App Router, let's not forget the solid foundation provided by the Pages Directory. A key difference between the two lies in route generation.</p>
<p>The Pages Directory automatically creates routes within the <code>pages</code> folder, whereas the App Router organizes routes within the <code>app</code> folder. This folder routing system maintains developer familiarity with how routing works while introducing a shift in route organization.</p>
<p>This distinction enables efficient route management and facilitates a seamless transition between the two routing mechanisms.</p>
<h3 id="heading-how-to-set-up-the-pages-directory">How to Set Up the Pages Directory</h3>
<p>To set up the Pages Directory for routing, you must first create a Next application. You can do this by running the command below on your local or code editor's terminal:</p>
<pre><code class="lang-bash">npx-create-next-app your-app-name
</code></pre>
<p>A list of configuration options appear underneath your command. Select "No" for <code>App Router</code> during the application setup. This creates a pages folder from which you can create routes.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/Folder-Directory-Setup-2.png" alt="Image" width="600" height="400" loading="lazy">
<em>Folder directory installation and setup</em></p>
<h3 id="heading-how-to-create-a-route-with-pages-directory">How to Create a Route with Pages Directory</h3>
<p>To create a route, create a folder in the pages folder and call it whatever you want the route to be (<strong>about</strong>, for example).</p>
<p>Then nest an <strong>index.js</strong> file in the <strong>about</strong> folder and fill it in with whatever content you want.</p>
<p>To route between pages, you can use the Next.js <code>link</code> component and pass in the corresponding URL you wish to route to.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/Folder-Directory-Example---3.png" alt="Image" width="600" height="400" loading="lazy">
<em>Folder directory example</em></p>
<p>Here's the result:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/Implementing-folder-routing.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Implementing routing using the folder directory</em></p>
<h3 id="heading-limitations-of-the-pages-directory">Limitations of the Pages Directory</h3>
<p>The Pages Directory provides a great way to structure routes in a Next.js application, but it has some limitations. Here are a few things to keep in mind:</p>
<ul>
<li>Static exports: The Pages Directory configuration relies on dynamic routes generated using <code>getStaticProps</code> and <code>getStaticPaths</code>. This means that not all pages in the directory can be statically exported.</li>
<li>Edge Runtime configuration: If you're using the Edge Runtime, you may need to do extra configuration beyond what's possible in the Pages Directory.</li>
<li>Internationalization routing: While Next.js supports internationalization routing, you need to configure locales, default locales, and domain-specific locales in the <strong>next.config.js</strong> file instead of the Pages Directory.</li>
<li>Serverless functions: API routes defined in the Pages Directory can handle basic API functionality, but more complex serverless functions may need extra configuration and alternative file placement.</li>
<li>Statically generated pages distribution: Statically generated pages may not be optimized for visitors without additional CDN configuration or "vendoring". This can impact the performance and distribution of statically generated pages. </li>
</ul>
<h2 id="heading-how-the-app-router-works-in-nextjs">How the App Router Works in Next.js</h2>
<p>The App Router is the fresh face on the Next.js scene, designed to address some of the limitations of the Pages Directory approach. While the app router still uses the folder directory for routing, it does so with a slightly different convention.</p>
<h3 id="heading-how-to-setup-the-app-router">How to Setup the App Router</h3>
<p>To set up the App router , follow the same installation process as mentioned in the pages directory, but opt for "Yes" when prompted to use the <code>App Router</code> during setup. This creates an <strong>app</strong> directory.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/App-router-Setup-2.png" alt="Image" width="600" height="400" loading="lazy">
<em>App Router installation and setup</em></p>
<h3 id="heading-how-to-create-a-route-with-app-router">How to Create a Route with App Router</h3>
<p>Routing with the App Router also involves creating folders but within the <strong>app</strong> directory. Nest a <strong>page.js</strong> file within the appropriate folder to define your route.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/App-router-Example-2.png" alt="Image" width="600" height="400" loading="lazy">
<em>Folder directory example</em></p>
<p>Here's the result:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/Implementing-app-routing.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Implementing routing using the app router</em></p>
<h2 id="heading-features-of-app-router-in-nextjs">Features of App Router in Next.js</h2>
<p>Apart from routing, App Router boasts a range of other features, including:</p>
<h3 id="heading-layout-component">Layout Component</h3>
<p>A layout component is a versatile UI element that shapes a page's structure. It can include components like headers, footers, and sidebars, and even offer shared functions like navigation.</p>
<p>Layout components work with routing, enabling smooth transitions between app pages. Since the layout component remains active when routes change, its state is retained, ensuring consistent and reusable layouts with minimal effort. </p>
<p>This component is designed to receive a <code>children</code> prop and wrap all page files in the same directory with it:</p>
<pre><code class="lang-js"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">layout</span>(<span class="hljs-params">{ children }</span>) </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">"layout"</span>&gt;</span>{children}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>;
}
</code></pre>
<p>Here’s an example that uses a layout component (a grey box) like the one in the code above between the user page and the settings page:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/Layout-example-2.png" alt="Image" width="600" height="400" loading="lazy">
<em>Creating a layout component that shares styles with its sibling pages</em></p>
<p>In the image above, the <strong>layout.js</strong> component is shared by both the user and settings pages. So both pages will have the styles and logic in the layout component.</p>
<p>And the result:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/Implementing-layouts.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Implementing the layout component on the user and settings page</em></p>
<h3 id="heading-nested-layouts">Nested Layouts</h3>
<p>These are layouts defined inside folders and apply to specific route segments and render when those segments are active. It allows you to define multiple levels of layout components, each enclosing the content of its child components. </p>
<p>This feature provides a flexible and modular way to structure your application's UI.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/nested-layouts.png" alt="Image" width="600" height="400" loading="lazy">
<em>Demonstrating how layout work with sibling and child pages</em></p>
<p>In the diagram above, the styles and logic in the first layout file applies to all pages inside the <strong>dashboard</strong> directory, while the second layout file applies to the pages in the <strong>developer</strong> directory.</p>
<h3 id="heading-template-components">Template Components</h3>
<p>Template components are like layouts, but they create a new instance for each child on navigation. This means recreating DOM elements, losing state, and resetting effects every time the route changes. </p>
<p>You can use them for things like tracking page views or interactive widgets. You can create a template by exporting a default React component from a <code>template.js</code> file. This component should be designed to receive a children prop.</p>
<pre><code class="lang-js"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Template</span>(<span class="hljs-params">{ children }</span>) </span>{
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>{children}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
}
</code></pre>
<h3 id="heading-loading-component">Loading Component</h3>
<p>This component can be made in any app folder directory. It auto-wraps pages with a React suspense boundary (that is, a component that helps manage loading moments when components need to fetch data or resources asynchronously). It shows on the first load and during sibling route navigation.</p>
<p>It looks something like this under the hood:</p>
<pre><code class="lang-js">&lt;Suspense fallback={<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Loading</span> /&gt;</span></span>}&gt;
   <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">YourComponent</span> /&gt;</span></span>
&lt;/Suspense&gt;
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/loading-component.png" alt="Image" width="600" height="400" loading="lazy">
<em>Showcasing the loading component in use</em></p>
<h3 id="heading-streaming">Streaming</h3>
<p>This involves sending parts of a webpage progressively from the server to the user's device. Unlike the traditional Server-Side Rendering (SSR), where all the data must be fetched before rendering, streaming sends smaller chunks of HTML as they're ready. </p>
<p><strong>Before streaming</strong></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/Before-streaming.png" alt="Image" width="600" height="400" loading="lazy">
<em>Displaying how SSR worked before stream was introduced</em></p>
<p>In the image above, no content is displayed while the page is being rendered. The component waits until all the contents are ready.</p>
<p><strong>Using streaming</strong></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/using-streaming.png" alt="Image" width="600" height="400" loading="lazy">
<em>How SSR now works with streaming</em></p>
<p>In the image above, the component doesn't wait for all the page content, it renders each one as soon as it's ready. </p>
<p>This speeds up the initial page display, prioritizing higher-priority components for early interactivity. Streaming reduces [Time To First Byte](https://en.wikipedia.org/wiki/Time_to_first_byte#:~:text=Time%20to%20first%20byte%20(TTFB,received%20by%20the%20client's%20browser.) (TTFB), enhances interactivity, and works well with React's component model.</p>
<p>It's works by using the <code>&lt;Suspense&gt;</code> component, improving loading and user experience, especially on slower devices.</p>
<h3 id="heading-error-component">Error Component</h3>
<p>This component confines errors to the app's tiniest section. Making an error file auto-encloses the page with a React error boundary. Any error within this file's folder swaps the component with its contents.</p>
<p>The error component is rendered like this behind the scenes:</p>
<pre><code class="lang-js">&lt;Layout&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ErrorBoundary</span> <span class="hljs-attr">fallback</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">Error</span> /&gt;</span>}&gt;
    <span class="hljs-tag">&lt;<span class="hljs-name">Page</span>/&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">ErrorBoundary</span>&gt;</span></span>
&lt;/Layout&gt;
</code></pre>
<p>And shows something like this;</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/error-layout.png" alt="Image" width="600" height="400" loading="lazy">
<em>Showcasing the error component in the case of an error</em></p>
<h3 id="heading-route-groups">Route Groups</h3>
<p>Route Groups organize routes in the app directory without altering URL paths. Enclosing a folder name in parentheses creates a Route Group that keeps related routes together. </p>
<p>This allows for logical grouping, nested layouts, and a clean URL structure. That is:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/route-groups.png" alt="Image" width="600" height="400" loading="lazy">
<em>How to use route groups to organize routes</em></p>
<p>In the example above, authentication pages are grouped together for better organization, without altering URL structure.</p>
<h3 id="heading-server-components">Server Components</h3>
<p>Server components, a prime addition to the App Router, renders on the server and streams to the client. This accelerates page loading and enhances performance. They speed up page load times as different page contents are loaded in small chunks and independently.</p>
<p>Note that they don't support client-side actions like click events and React hooks (<code>useState</code> , <code>useRef</code>). To convert a server component into a client component, mark it with <code>use client</code> at the beginning of the file. </p>
<p>Here's an example:</p>
<pre><code class="lang-js"><span class="hljs-string">'use client'</span>

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

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Counter</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [count, setCount] = useState(<span class="hljs-number">0</span>)

  <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">p</span>&gt;</span>You clicked {count} times<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> setCount(count + 1)}&gt;Click me<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>
  )
}
</code></pre>
<h3 id="heading-data-fetching">Data Fetching</h3>
<p>Server components bring a fresh data fetching pattern, allowing <code>async</code> components to fetch data within them. This reduces reliance on APIs like <code>getServerSideProps</code>. </p>
<p>To fetch data, mark a component as <code>async</code> and use the fetch function within:</p>
<pre><code class="lang-js"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Home</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">"https://api.adviceslip.com/advice"</span>);
  <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> response.json();
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">main</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Home Page<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>{data.slip.advice}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span></span>
  );
}
</code></pre>
<p>And get your result on the page like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/fetch.png" alt="Image" width="600" height="400" loading="lazy">
<em>Using the fetch function in a server component</em></p>
<p>The App Router also caches the fetched data on the server, eliminating the need to re-fetch that data on every request, unless a revalidation parameter is passed in in the fetch function:  </p>
<pre><code class="lang-js"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Home</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">"https://api.adviceslip.com/advice"</span>, {
    <span class="hljs-attr">next</span>: { <span class="hljs-attr">revalidate</span>: <span class="hljs-number">5</span> },
  });
</code></pre>
<p>The code above causes a re-fetch of new data every 5 seconds.</p>
<h3 id="heading-built-in-seo">Built-in SEO</h3>
<p>Another feature of the Next.js App router is the built-in Metadata API, used as an SEO tool to optimize websites for search engines. This API provides a range of SEO settings, including the <a target="_blank" href="https://ogp.me/">Open Graph protocol</a>, to enhance the visibility of websites to search engines.</p>
<p>There are two methods of implementing this — static and dynamic methods.</p>
<p>Here's the static approach:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { Metadata } <span class="hljs-keyword">from</span> <span class="hljs-string">"next"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> Metadata = {
  <span class="hljs-attr">title</span>: <span class="hljs-string">"Blog page title"</span>,
  <span class="hljs-attr">description</span>: <span class="hljs-string">"Blog page description"</span>,
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">page</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">main</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Blog Page<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span></span>
  );
}
</code></pre>
<p>Here's the dynamic approach using the <code>getMetadata</code> function:</p>
<pre><code class="lang-js"><span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">generateMetadata</span>(<span class="hljs-params">{ params, searchParams}</span>) </span>{

<span class="hljs-keyword">const</span> id= params.id

   <span class="hljs-keyword">const</span> blog= <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">`https://blog/<span class="hljs-subst">${id}</span>`</span>).then(<span class="hljs-function">(<span class="hljs-params">res</span>) =&gt;</span>res.json()

  <span class="hljs-keyword">return</span> { 
        <span class="hljs-attr">title</span>: blog.title,
        <span class="hljs-attr">Description</span>: blog.description,
   };

}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Page</span>(<span class="hljs-params">{ params, searchParams }</span>) </span>{}
</code></pre>
<h2 id="heading-advanced-features-of-app-router-in-nextjs">Advanced Features of App Router in Next.js</h2>
<p>While we've covered notable aspects, the App Router's capabilities extend beyond what we've discussed. Features like server actions, data revalidation, parallel routes, and route interception provide further utility.</p>
<p>As always, you can turn to the <a target="_blank" href="https://nextjs.org/docs">Next.js docs</a> for a wider range of information to elevate your understanding and mastery of these additions to the Next.js ecosystem.</p>
<h2 id="heading-pages-directory-vs-app-router-which-to-use">Pages Directory vs App Router - Which to Use?</h2>
<p>In the rapidly evolving world of web development, it's easy to get caught up in the hype surrounding new technologies and tools. However, when it comes to choosing between the Pages Directory and the App Router, it's important to strike a balance between excitement and caution.</p>
<p>Both options have their own strengths and considerations, and understanding your needs and goals will help you determine which one to use in a given context.</p>
<h3 id="heading-selecting-the-appropriate-tool-for-your-requirements">Selecting the Appropriate Tool for Your Requirements</h3>
<p>When making the choice between the Pages Directory and the App Router, it is crucial to take into account your individual needs and objectives. Here are a few factors to bear in mind:</p>
<ol>
<li><p>Stability vs Flexibility: If your main concerns are stability and user-friendliness, the Pages Directory is a dependable option. It provides a solid foundation for simple routing tasks. However, if you require more flexibility and the ability to customize, the App Router might be a more suitable choice.</p>
</li>
<li><p>Development speed: The Pages Directory offers a fast and efficient approach to creating and managing pages, making it ideal for speedy development. Conversely, due to its advanced capabilities, the App Router may cause more upfront configuration and development effort.</p>
</li>
<li><p>Complex routing scenarios: If your application requires intricate routing scenarios like nested routes or dynamic routing based on external data, the App Router's programmability can be a significant advantage.</p>
</li>
</ol>
<p>Ultimately, the key to making well-informed decisions lies in staying knowledgeable about the capabilities and trade-offs of both the Pages Directory and the App Router.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In summary, you now have a good understanding of Next.js's App Router and its features.</p>
<p>You have learned how to structure routes using both the Pages Directory and the App Router, as well as advanced features such as layout components, server components, and data fetching.</p>
<p>By exploring these topics, you have not only gained insights into the capabilities of these tools. You've also learned how to choose between the new approach (App Router) and the old approach of using the Pages Directory.</p>
<p>With this knowledge, you are well-prepared to make informed decisions and create exceptional web experiences in the ever-changing landscape of web development. </p>
<h2 id="heading-contact-information">Contact Information</h2>
<p>Want to connect or contact me? Feel free to hit me up on the following:</p>
<ul>
<li>Twitter, sorry (X) 😂: <a target="_blank" href="https://twitter.com/JajaDavid8">@jajadavid8</a></li>
<li>LinkedIn: <a target="_blank" href="https://www.linkedin.com/in/david-jaja-8084251b4/">David Jaja</a></li>
<li>Email: Jajadavidjid@gmail.com</li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
