<?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[ ReactHooks - 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[ ReactHooks - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Tue, 22 Sep 2026 21:39:55 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/reacthooks/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to Simplify Your React Components with Derived State ]]>
                </title>
                <description>
                    <![CDATA[ React simplifies building user interfaces with hooks like useState for managing dynamic values. But it's common to overuse useState. This often leads to duplicated data and unnecessary complexity. For instance, you might store a full name in state wh... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/simplify-react-components-with-derived-state/</link>
                <guid isPermaLink="false">6924c6fb01ae89275dfb14f6</guid>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ TypeScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ ReactHooks ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Olaleye Blessing ]]>
                </dc:creator>
                <pubDate>Mon, 24 Nov 2025 20:58:35 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1764017894421/6bbd5cf2-c221-490c-891a-bf984cfaa92c.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>React simplifies building user interfaces with hooks like <code>useState</code> for managing dynamic values. But it's common to overuse <code>useState</code>. This often leads to duplicated data and unnecessary complexity.</p>
<p>For instance, you might store a full name in state when it can be calculated from first and last name props, or duplicate fetched data from a library like React Query. This creates issues like harder debugging, extra re-renders, and synchronization problems.</p>
<p>In this tutorial, you'll learn how to use derived state to improve your components. By the end, you'll know when to derive state instead of storing it, making your React code cleaner and more maintainable.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ol>
<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-derived-state">What Is a Derived State?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-derive-state-from-existing-data">How to Derive State From Existing Data</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-how-to-derive-state-from-props-or-other-state">How to Derive State From Props or Other State</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-derive-state-from-a-url">How to Derive State From a URL</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-derive-state-from-external-data">How to Derive State From External Data</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-prevent-recalculation-of-a-derived-state">How to Prevent Recalculation of a Derived State</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-when-to-use-usestate">When to Use useState</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-controlled-input">Controlled Input</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-independent-state-changes">Independent State Changes</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ol>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>Before you move on, make sure you have:</p>
<ul>
<li><p>Basic knowledge of JavaScript, TypeScript, React, and React hooks</p>
</li>
<li><p>Understanding of asynchronous calls</p>
</li>
<li><p>A simple React development setup.</p>
</li>
</ul>
<p>If you don’t have a React development setup, you can head over to the <a target="_blank" href="https://github.com/Olaleye-Blessing/freecodecamp-derived-states">derived-state repo</a>. The repo has been set up with <a target="_blank" href="https://reactrouter.com/">React Router</a> and <a target="_blank" href="https://tanstack.com/query/latest/docs/framework/react/overview">React Query</a>. Run the commands below to set it up:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># clone the repo</span>
git <span class="hljs-built_in">clone</span> &lt;https://github.com/Olaleye-Blessing/freecodecamp-derived-states.git&gt;

<span class="hljs-comment"># navigate to the folder</span>
<span class="hljs-built_in">cd</span> freecodecamp-derived-states

<span class="hljs-comment"># install the packages</span>
pnpm install

<span class="hljs-comment"># start development</span>
pnpm dev
</code></pre>
<h2 id="heading-what-is-a-derived-state">What Is a Derived State?</h2>
<p>A derived state is any value that can be calculated from existing data. This existing data can be from:</p>
<ul>
<li><p><strong>Props:</strong> Data passed from a parent component.</p>
</li>
<li><p><strong>Existing state:</strong> Other state variables already in your component.</p>
</li>
<li><p><strong>URL parameters:</strong> Data from routes or query strings.</p>
</li>
<li><p><strong>External data:</strong> Data from a fetching library like React Query.</p>
</li>
</ul>
<p>Storing derivable state in <code>useState</code> can create several issues. First, it can cause debugging problems: more state variables make it harder to trace data flow. The more states you have, the more the number of state changes you need to keep track of while debugging.</p>
<p>It can also cause unnecessary re-renders. React will trigger a re-render every time you call the state setter function.</p>
<p>Finally, there can be synchronization issues, as you’re forced to update the “derived state” anytime the source data changes manually. When similar data exists in multiple states, they can get out of sync.</p>
<h2 id="heading-how-to-derive-state-from-existing-data">How to Derive State From Existing Data</h2>
<p>Moving forward, we’ll explore common scenarios where you can derive state instead of storing it in another <code>useState</code>.</p>
<p>Note: All the code in this article is run in <a target="_blank" href="https://react.dev/reference/react/StrictMode">non-StrictMode</a>.</p>
<h3 id="heading-how-to-derive-state-from-props-or-other-state">How to Derive State From Props or Other State</h3>
<p>In this section, we’ll first examine the problems caused by using <code>useState</code> for derivable values. We’ll look at a form component that stores unnecessary states like full name, adult status, and a local copy of an email. You’ll see the re-renders in different scenarios and then learn how to refactor using derived state to remove these problems.</p>
<h4 id="heading-the-problem-with-extra-states">The Problem With Extra States</h4>
<p>Any value that comes directly from props or other state can be derived on the fly. Take the below as an example, where you pass an <code>email</code> prop to a form component:</p>
<pre><code class="lang-typescript">&lt;DetailForm email=<span class="hljs-string">"olaleyedev@gmail.com"</span> /&gt;
</code></pre>
<p>Here is how the form receives the email prop and also manages its own state:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { useEffect, useState, <span class="hljs-keyword">type</span> FormEventHandler } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-keyword">interface</span> DetailFormProps {
  email: <span class="hljs-built_in">string</span>;
}

<span class="hljs-keyword">const</span> DetailForm = <span class="hljs-function">(<span class="hljs-params">{ email }: DetailFormProps</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> [lastName, setLastName] = useState(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> [fullName, setFullName] = useState(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> [firstName, setFirstName] = useState(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> [age, setAge] = useState(<span class="hljs-number">0</span>);
  <span class="hljs-keyword">const</span> [isAdult, setIsAdult] = useState(<span class="hljs-literal">false</span>);
  <span class="hljs-keyword">const</span> [localEmail, setLocalEmail] = useState(email);

  useEffect(<span class="hljs-function">() =&gt;</span> {
    setLocalEmail(email);
  }, [email]);

  useEffect(<span class="hljs-function">() =&gt;</span> {
    setFullName(<span class="hljs-string">`<span class="hljs-subst">${firstName}</span> <span class="hljs-subst">${lastName}</span>`</span>.trim());
  }, [firstName, lastName]);

  useEffect(<span class="hljs-function">() =&gt;</span> {
    setIsAdult(age &gt; <span class="hljs-number">18</span>);
  }, [age]);

  <span class="hljs-keyword">const</span> submitForm: FormEventHandler&lt;HTMLFormElement&gt; = <span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> {
    e.preventDefault();
    <span class="hljs-built_in">console</span>.log({ fullName, age, isAdult });
  };

  <span class="hljs-built_in">console</span>.count(<span class="hljs-string">"-- Form render --"</span>);

  <span class="hljs-keyword">return</span> (
    &lt;form onSubmit={submitForm}&gt;
      &lt;div style={{ marginBottom: <span class="hljs-string">"1rem"</span> }}&gt;
        &lt;label
          htmlFor=<span class="hljs-string">"firstName"</span>
          style={{
            display: <span class="hljs-string">"inline-block"</span>,
            marginRight: <span class="hljs-string">"1rem"</span>,
            width: <span class="hljs-string">"10rem"</span>,
          }}
        &gt;
          First Name
        &lt;/label&gt;
        &lt;input
          id=<span class="hljs-string">"firstName"</span>
          <span class="hljs-keyword">type</span>=<span class="hljs-string">"text"</span>
          onChange={<span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> setFirstName(e.target.value)}
        /&gt;
      &lt;/div&gt;
      &lt;div style={{ marginBottom: <span class="hljs-string">"1rem"</span> }}&gt;
        &lt;label
          htmlFor=<span class="hljs-string">"lastName"</span>
          style={{
            display: <span class="hljs-string">"inline-block"</span>,
            marginRight: <span class="hljs-string">"1rem"</span>,
            width: <span class="hljs-string">"10rem"</span>,
          }}
        &gt;
          Last Name
        &lt;/label&gt;
        &lt;input
          id=<span class="hljs-string">"lastName"</span>
          <span class="hljs-keyword">type</span>=<span class="hljs-string">"text"</span>
          onChange={<span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> setLastName(e.target.value)}
        /&gt;
      &lt;/div&gt;
      &lt;div style={{ marginBottom: <span class="hljs-string">"1rem"</span> }}&gt;
        &lt;label
          htmlFor=<span class="hljs-string">"age"</span>
          style={{
            display: <span class="hljs-string">"inline-block"</span>,
            marginRight: <span class="hljs-string">"1rem"</span>,
            width: <span class="hljs-string">"10rem"</span>,
          }}
        &gt;
          Age
        &lt;/label&gt;
        &lt;input <span class="hljs-keyword">type</span>=<span class="hljs-string">"number"</span> onChange={<span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> setAge(<span class="hljs-built_in">Number</span>(e.target.value))} /&gt;
      &lt;/div&gt;
      &lt;p&gt;
        Your receipt will have{<span class="hljs-string">" "</span>}
        &lt;span
          style={{
            borderBottom: <span class="hljs-string">"1px solid #fffa"</span>,
            paddingBottom: <span class="hljs-string">"1px"</span>,
          }}
        &gt;
          {fullName.trim() || <span class="hljs-string">"-----"</span>}
        &lt;/span&gt;{<span class="hljs-string">" "</span>}
        <span class="hljs-keyword">as</span> the recipient<span class="hljs-string">'s name and will be sent to {localEmail || "-----"}.
      &lt;/p&gt;
      &lt;p&gt;
        {isAdult
          ? "You are allowed to order a drink."
          : "You are not allowed to order any drinks."}
      &lt;/p&gt;
      &lt;button type="submit" disabled={!isAdult}&gt;
        Submit
      &lt;/button&gt;
    &lt;/form&gt;
  );
};

export default DetailForm;</span>
</code></pre>
<p>The form component collects information from a user. It shows them more information based on their input and the provided email. It maintains some states to keep track of the user’s input.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762625903293/c952e785-2b37-4411-987f-01686db8f54e.png" alt="c952e785-2b37-4411-987f-01686db8f54e" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>While it looks simple, there are some issues with the way state is being used here.</p>
<p>First of all, a React component re-renders whenever any of its states change. Looking at the UI, the form should only re-render when users input their first name, last name, and age, or when the email prop changes from the parent. This means the form should keep track of just these three states internally, while deriving from the prop and other states.</p>
<p>But the form keeps track of three extra states (<code>fullName</code>, <code>isAdult</code>, and <code>localEmail</code>). This means that the form will re-render each time these extra states change.</p>
<p>Let’s see this in action:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762626688959/f381aa1f-6244-4065-aa36-123134f26b1b.gif" alt="f381aa1f-6244-4065-aa36-123134f26b1b" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>As you can see, the form re-rendered twice when the input field changed, instead of once. The form re-rendered the first time the user updated their first name. But for each time the first and last name changed, the second <code>useEffect</code> gets triggered.</p>
<pre><code class="lang-typescript">useEffect(<span class="hljs-function">() =&gt;</span> {
  setFullName(<span class="hljs-string">`<span class="hljs-subst">${firstName}</span> <span class="hljs-subst">${lastName}</span>`</span>.trim());
}, [firstName, lastName]);
</code></pre>
<p>This is to sync the <code>fullName</code> with the <code>firstName</code> and <code>lastName</code>. Updating the <code>fullName</code> causes the form to re-render the second time.</p>
<p>The same applies to the <code>isAdult</code> state. When the user updates their <code>age</code>, <code>setAge()</code> re-renders the form, and the third <code>useEffect</code> also causes another re-render.</p>
<h4 id="heading-handling-email-changes">Handling Email Changes</h4>
<p>Let’s see what happens when you update the email from the parent component. This is the code that allows you to update the email:</p>
<pre><code class="lang-typescript"><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> [email, setEmail] = useState(<span class="hljs-string">"olaleyedev@gmail.com"</span>);

  <span class="hljs-keyword">return</span> (
    &lt;&gt;
      &lt;div
        style={{
          marginBottom: <span class="hljs-string">"1rem"</span>,
          border: <span class="hljs-string">"1px solid #fff"</span>,
          paddingBottom: <span class="hljs-string">"1rem"</span>,
        }}
      &gt;
        &lt;h3&gt;Parent Component&lt;/h3&gt;
        &lt;input
          style={{ padding: <span class="hljs-string">"0.4rem 0.8rem"</span> }}
          <span class="hljs-keyword">type</span>=<span class="hljs-string">"email"</span>
          value={email}
          onChange={<span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> setEmail(e.target.value)}
        /&gt;
      &lt;/div&gt;
      &lt;DetailForm email={email} /&gt;
    &lt;/&gt;
  );
}
</code></pre>
<p>The parent component keeps track of the user’s email and also updates it through an <code>input</code> element.</p>
<p>Note: In the <code>&lt;Detail /&gt;</code> component, I’ve removed the <code>useEffect</code>s that sync the <code>fullName</code> and <code>isAdult</code>. This is to focus mainly on the <code>email</code> prop. The form component now has this:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { useEffect, useState, <span class="hljs-keyword">type</span> FormEventHandler } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-keyword">interface</span> DetailFormProps {
  email: <span class="hljs-built_in">string</span>;
}

<span class="hljs-keyword">const</span> DetailForm = <span class="hljs-function">(<span class="hljs-params">{ email }: DetailFormProps</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> [lastName, setLastName] = useState(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> [fullName, setFullName] = useState(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> [firstName, setFirstName] = useState(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> [age, setAge] = useState(<span class="hljs-number">0</span>);
  <span class="hljs-keyword">const</span> [isAdult, setIsAdult] = useState(<span class="hljs-literal">false</span>);
  <span class="hljs-keyword">const</span> [localEmail, setLocalEmail] = useState(email);

  useEffect(<span class="hljs-function">() =&gt;</span> {
    setLocalEmail(email);
  }, [email]);

  <span class="hljs-keyword">const</span> submitForm: FormEventHandler&lt;HTMLFormElement&gt; = <span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> {
    e.preventDefault();
    <span class="hljs-built_in">console</span>.log({ fullName, age, isAdult });
  };

  <span class="hljs-built_in">console</span>.count(<span class="hljs-string">"-- Form render --"</span>);

  <span class="hljs-keyword">return</span> &lt;form onSubmit={submitForm}&gt;{<span class="hljs-comment">/* Rest */</span>}&lt;/form&gt;;
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> DetailForm;
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762626841744/9beffe7d-2513-4d3e-9970-21477b16161e.gif" alt="9beffe7d-2513-4d3e-9970-21477b16161e" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>Updating the email from the parent component causes the detail form to have an extra re-render. Because you are saving the email to a local state, any change to the <code>email</code> prop triggers the <code>useEffect</code> to update the state, causing an extra re-render. Your UI will show stale data without <code>useEffect</code>.</p>
<h4 id="heading-how-to-solve-this-with-derived-states">How to Solve This with Derived States</h4>
<p>You can solve all these extra re-renders by using derived states. Neither <code>fullName</code> nor <code>isAdult</code> directly needs the user’s input for us to know their value. You can calculate their value when their dependent states change without using <code>useEffect</code>. Likewise, you can derive the <code>email</code> directly by using the prop value on the fly.</p>
<pre><code class="lang-diff">import { useEffect, useState, type FormEventHandler } from "react";

interface DetailFormProps {
  email: string;
}

const DetailForm = ({ email }: DetailFormProps) =&gt; {
  const [lastName, setLastName] = useState("");
  const [firstName, setFirstName] = useState("");
<span class="hljs-deletion">- const [fullName, setFullName] = useState("");</span>
  const [age, setAge] = useState(0);
<span class="hljs-deletion">- const [isAdult, setIsAdult] = useState(false);</span>
<span class="hljs-deletion">- const [localEmail, setLocalEmail] = useState(email);</span>

<span class="hljs-deletion">- useEffect(() =&gt; {</span>
<span class="hljs-deletion">-   setFullName(`${firstName} ${lastName}`.trim());</span>
<span class="hljs-deletion">- }, [firstName, lastName]);</span>

<span class="hljs-deletion">- useEffect(() =&gt; {</span>
<span class="hljs-deletion">-   setIsAdult(age &gt; 18);</span>
<span class="hljs-deletion">- }, [age]);</span>

<span class="hljs-deletion">- useEffect(() =&gt; {</span>
<span class="hljs-deletion">-   setLocalEmail(email);</span>
<span class="hljs-deletion">- }, [email]);</span>

<span class="hljs-addition">+ const fullName = `${firstName} ${lastName}`.trim();</span>
<span class="hljs-addition">+ const isAdult = age &gt; 18;</span>

  const submitForm: FormEventHandler&lt;HTMLFormElement&gt; = (e) =&gt; {
    e.preventDefault();
<span class="hljs-deletion">-   console.log({ fullName, age, isAdult, email: localEmail });</span>
<span class="hljs-addition">+   console.log({ fullName, age, isAdult, email });</span>
  };
};

export default DetailForm;
</code></pre>
<p>The form now stores the necessary state, <code>lastName</code>, <code>firstName</code>, and <code>age</code>. The <code>fullName</code> and <code>isAdult</code> values are derived directly from their dependent values.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762627041623/69004769-ddd9-470c-9212-ba7711350b57.gif" alt="69004769-ddd9-470c-9212-ba7711350b57" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>As you can see with the derived state, we have 0 extra re-renders. The form re-rendered only when it should. The form re-rendered once when each input value changed, not twice. Also, when the email changes in the parent component, there is only one re-render.</p>
<h3 id="heading-how-to-derive-state-from-a-url">How to Derive State From a URL</h3>
<p>You can also use a URL to save dynamic data through route parameters or query strings. Every routing library provides some hooks to access this data.</p>
<p>For example, React Router provides <code>useParams</code> or <code>useSearchParams</code>. In most cases, the returned values from these hooks don’t need to go into <code>useState</code> again – as this would mean keeping track of two storage, <code>useState</code> and <code>URL</code>.</p>
<p>Now, we’ll look at some examples using search parameters from React Router. You’ll first see an example that overuses <code>useState</code> and causes extra re-renders and sync issues. Then you’ll see its derived solution.</p>
<h4 id="heading-syncing-with-useeffect">Syncing with <code>useEffect</code></h4>
<p>The component you will be using is a filter component:</p>
<pre><code class="lang-typescript"><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> { useSearchParams } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-router"</span>;

<span class="hljs-keyword">const</span> Products = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> [searchParams, setSearchParams] = useSearchParams();
  <span class="hljs-keyword">const</span> [searchQuery, setSearchQuery] = useState(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> [selectedCategory, setSelectedCategory] = useState(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> [selectedMaterial, setSelectedMaterial] = useState(<span class="hljs-string">""</span>);

  useEffect(<span class="hljs-function">() =&gt;</span> {
    setSearchQuery(searchParams.get(<span class="hljs-string">"search"</span>) || <span class="hljs-string">""</span>);
    setSelectedCategory(searchParams.get(<span class="hljs-string">"category"</span>) || <span class="hljs-string">""</span>);
    setSelectedMaterial(searchParams.get(<span class="hljs-string">"material"</span>) || <span class="hljs-string">""</span>);
  }, [searchParams]);

  <span class="hljs-built_in">console</span>.count(<span class="hljs-string">"__ RENDERDED ___"</span>);

  <span class="hljs-keyword">return</span> (
    &lt;div
      style={{
        display: <span class="hljs-string">"flex"</span>,
        alignItems: <span class="hljs-string">"center"</span>,
        justifyContent: <span class="hljs-string">"center"</span>,
        gap: <span class="hljs-string">"1rem"</span>,
      }}
    &gt;
      &lt;input value={searchQuery} /&gt;
      &lt;select value={selectedCategory}&gt;
        &lt;option value=<span class="hljs-string">""</span>&gt;All Categories&lt;/option&gt;
        &lt;option value=<span class="hljs-string">"electronics"</span>&gt;Electronics&lt;/option&gt;
        &lt;option value=<span class="hljs-string">"clothing"</span>&gt;Clothing&lt;/option&gt;
      &lt;/select&gt;
      &lt;select value={selectedMaterial}&gt;
        &lt;option value=<span class="hljs-string">""</span>&gt;All Material&lt;/option&gt;
        &lt;option value=<span class="hljs-string">"leather"</span>&gt;Leather&lt;/option&gt;
        &lt;option value=<span class="hljs-string">"silk"</span>&gt;Silk&lt;/option&gt;
      &lt;/select&gt;
      &lt;button&gt;Clear Filters&lt;/button&gt;
    &lt;/div&gt;
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Products;
</code></pre>
<p>This component allows users to search for a product and/or filter by category and materials. While it looks simple, this component has all the problems mentioned earlier.</p>
<p>Let’s see what happens when the component mounts with no filter and predefined filters.</p>
<h5 id="heading-with-no-filter">With no filter:</h5>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762627432720/fb1ffe32-b3ae-4506-9a33-cdd42cffb5dd.gif" alt="fb1ffe32-b3ae-4506-9a33-cdd42cffb5dd" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>The component only renders once when there's no filter. This is good.</p>
<h5 id="heading-with-a-predefined-filter">With a predefined filter:</h5>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762627673969/3a29eb6d-694d-4499-8f78-06cd8702ae3d.gif" alt="3a29eb6d-694d-4499-8f78-06cd8702ae3d" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>It renders twice because you are trying to make sure your <code>useState</code>s are in sync with the <code>URL</code> by using <code>useEffect</code>. The component renders the first time it mounts, then re-renders because of the dependency in <code>useEffect</code>.</p>
<h4 id="heading-initializing-usestate-directly">Initializing <code>useState</code> Directly</h4>
<p>You could be thinking that it’s better to move the getters into the <code>useState</code>s directly, which truly solves the re-rendering case when the component mounts.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> Products = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> [searchParams, setSearchParams] = useSearchParams();
  <span class="hljs-keyword">const</span> [searchQuery, setSearchQuery] = useState(
    searchParams.get(<span class="hljs-string">"search"</span>) || <span class="hljs-string">""</span>,
  );
  <span class="hljs-keyword">const</span> [selectedCategory, setSelectedCategory] = useState(
    searchParams.get(<span class="hljs-string">"category"</span>) || <span class="hljs-string">""</span>,
  );
  <span class="hljs-keyword">const</span> [selectedMaterial, setSelectedMaterial] = useState(
    searchParams.get(<span class="hljs-string">"material"</span>) || <span class="hljs-string">""</span>,
  );

  <span class="hljs-comment">// prev code</span>
};
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762627883127/76b4af17-a0c6-4f7d-bc40-fbf013fb2ad9.gif" alt="76b4af17-a0c6-4f7d-bc40-fbf013fb2ad9" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>As you can see, the component only renders once. There is no more <code>useEffect</code> to trigger another re-render.</p>
<p>Just keep in mind that this isn’t a solution yet. It has other problems you’ll see soon.</p>
<p>What happens when any of the filtering changes or when you enter a search query?</p>
<h4 id="heading-handling-changes">Handling Changes</h4>
<p>Both solution shows that you have unnecessary re-renders. This is because you have to keep two states in sync: both the <code>useState</code>s and the <code>URL</code>.</p>
<pre><code class="lang-typescript"><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> { useSearchParams } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-router"</span>;

<span class="hljs-keyword">const</span> Products = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-comment">// prev code</span>

  <span class="hljs-keyword">const</span> handleSearchChange = <span class="hljs-function">(<span class="hljs-params">query: <span class="hljs-built_in">string</span></span>) =&gt;</span> {
    setSearchQuery(query);
    setSearchParams(<span class="hljs-function">(<span class="hljs-params">prev</span>) =&gt;</span> {
      <span class="hljs-keyword">const</span> newParams = <span class="hljs-keyword">new</span> URLSearchParams(prev);
      <span class="hljs-keyword">if</span> (query) {
        newParams.set(<span class="hljs-string">"search"</span>, query);
      } <span class="hljs-keyword">else</span> {
        newParams.delete(<span class="hljs-string">"search"</span>);
      }
      <span class="hljs-keyword">return</span> newParams;
    });
  };

  <span class="hljs-keyword">const</span> handleCategoryChange = <span class="hljs-function">(<span class="hljs-params">category: <span class="hljs-built_in">string</span></span>) =&gt;</span> {
    setSelectedCategory(category);
    setSearchParams(<span class="hljs-function">(<span class="hljs-params">prev</span>) =&gt;</span> {
      <span class="hljs-keyword">const</span> newParams = <span class="hljs-keyword">new</span> URLSearchParams(prev);
      <span class="hljs-keyword">if</span> (category) {
        newParams.set(<span class="hljs-string">"category"</span>, category);
      } <span class="hljs-keyword">else</span> {
        newParams.delete(<span class="hljs-string">"category"</span>);
      }
      <span class="hljs-keyword">return</span> newParams;
    });
  };

  <span class="hljs-keyword">const</span> handleMaterialChange = <span class="hljs-function">(<span class="hljs-params">material: <span class="hljs-built_in">string</span></span>) =&gt;</span> {
    setSelectedMaterial(material);
    setSearchParams(<span class="hljs-function">(<span class="hljs-params">prev</span>) =&gt;</span> {
      <span class="hljs-keyword">const</span> newParams = <span class="hljs-keyword">new</span> URLSearchParams(prev);
      <span class="hljs-keyword">if</span> (material) {
        newParams.set(<span class="hljs-string">"material"</span>, material);
      } <span class="hljs-keyword">else</span> {
        newParams.delete(<span class="hljs-string">"material"</span>);
      }
      <span class="hljs-keyword">return</span> newParams;
    });
  };

  <span class="hljs-keyword">const</span> clearFilters = <span class="hljs-function">() =&gt;</span> {
    setSearchQuery(<span class="hljs-string">""</span>);
    setSelectedCategory(<span class="hljs-string">""</span>);
    setSelectedMaterial(<span class="hljs-string">""</span>);
    setSearchParams({});
  };

  <span class="hljs-built_in">console</span>.count(<span class="hljs-string">"__ RENDERDED ___"</span>);

  <span class="hljs-keyword">return</span> (
    &lt;div
      style={{
        display: <span class="hljs-string">"flex"</span>,
        alignItems: <span class="hljs-string">"center"</span>,
        justifyContent: <span class="hljs-string">"center"</span>,
        gap: <span class="hljs-string">"1rem"</span>,
      }}
    &gt;
      &lt;input
        value={searchQuery}
        onChange={<span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> handleSearchChange(e.target.value)}
      /&gt;
      &lt;select
        value={selectedCategory}
        onChange={<span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> handleCategoryChange(e.target.value)}
      &gt;
        {<span class="hljs-comment">/* prev options */</span>}
      &lt;/select&gt;
      &lt;select
        value={selectedMaterial}
        onChange={<span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> handleMaterialChange(e.target.value)}
      &gt;
        {<span class="hljs-comment">/* prev options */</span>}
      &lt;/select&gt;
      &lt;button onClick={clearFilters}&gt;Clear Filters&lt;/button&gt;
    &lt;/div&gt;
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Products;
</code></pre>
<p>Because you are tracking the values in <code>useState</code>, you need to update the <code>useState</code> first before updating the <code>URL</code>. The UI won’t get updated if you update the <code>URL</code> without updating the <code>useState</code>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762628106580/c28d2453-9faa-460d-9cfa-d000b9ed41a4.gif" alt="c28d2453-9faa-460d-9cfa-d000b9ed41a4" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>Notice that each change leads to 2-3 re-renders.</p>
<h4 id="heading-using-derived-state">Using Derived State</h4>
<p>Using a derived state will solve all the issues you encountered. Your state can be derived directly from the <code>URL</code> without using <code>useState</code> and/or <code>useEffect</code>.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { useSearchParams } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-router"</span>;

<span class="hljs-keyword">const</span> Products = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> [searchParams, setSearchParams] = useSearchParams();

  <span class="hljs-keyword">const</span> searchQuery = searchParams.get(<span class="hljs-string">"search"</span>) || <span class="hljs-string">""</span>;
  <span class="hljs-keyword">const</span> selectedCategory = searchParams.get(<span class="hljs-string">"category"</span>) || <span class="hljs-string">""</span>;
  <span class="hljs-keyword">const</span> selectedMaterial = searchParams.get(<span class="hljs-string">"material"</span>) || <span class="hljs-string">""</span>;

  <span class="hljs-keyword">const</span> updateFilter = <span class="hljs-function">(<span class="hljs-params">key: <span class="hljs-built_in">string</span>, value: <span class="hljs-built_in">string</span></span>) =&gt;</span> {
    setSearchParams(<span class="hljs-function">(<span class="hljs-params">prev</span>) =&gt;</span> {
      <span class="hljs-keyword">const</span> newParams = <span class="hljs-keyword">new</span> URLSearchParams(prev);
      <span class="hljs-keyword">if</span> (value) {
        newParams.set(key, value);
      } <span class="hljs-keyword">else</span> {
        newParams.delete(key);
      }
      <span class="hljs-keyword">return</span> newParams;
    });
  };

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

  <span class="hljs-built_in">console</span>.count(<span class="hljs-string">"__ RENDERDED ___"</span>);

  <span class="hljs-keyword">return</span> (
    &lt;div
      style={{
        display: <span class="hljs-string">"flex"</span>,
        alignItems: <span class="hljs-string">"center"</span>,
        justifyContent: <span class="hljs-string">"center"</span>,
        gap: <span class="hljs-string">"1rem"</span>,
      }}
    &gt;
      &lt;input
        value={searchQuery}
        onChange={<span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> updateFilter(<span class="hljs-string">"search"</span>, e.target.value)}
      /&gt;
      &lt;select
        value={selectedCategory}
        onChange={<span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> updateFilter(<span class="hljs-string">"category"</span>, e.target.value)}
      &gt;
        &lt;option value=<span class="hljs-string">""</span>&gt;All Categories&lt;/option&gt;
        &lt;option value=<span class="hljs-string">"electronics"</span>&gt;Electronics&lt;/option&gt;
        &lt;option value=<span class="hljs-string">"clothing"</span>&gt;Clothing&lt;/option&gt;
      &lt;/select&gt;
      &lt;select
        value={selectedMaterial}
        onChange={<span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> updateFilter(<span class="hljs-string">"material"</span>, e.target.value)}
      &gt;
        &lt;option value=<span class="hljs-string">""</span>&gt;All Material&lt;/option&gt;
        &lt;option value=<span class="hljs-string">"leather"</span>&gt;Leather&lt;/option&gt;
        &lt;option value=<span class="hljs-string">"silk"</span>&gt;Silk&lt;/option&gt;
      &lt;/select&gt;
      &lt;button onClick={clearFilters}&gt;Clear Filters&lt;/button&gt;
    &lt;/div&gt;
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Products;
</code></pre>
<p>You now read your values directly from the <code>URL</code>. You also update the <code>URL</code> only whenever any of the values change.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762628297681/03d0eabb-1030-4e70-83a0-11feb7f4e9e9.gif" alt="03d0eabb-1030-4e70-83a0-11feb7f4e9e9" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>Notice that you have no re-render when the component mounts, even with predefined filters. The component re-renders once when any filtering key changes.</p>
<p>This approach gives several benefits:</p>
<ul>
<li><p>You don’t need <code>useEffect</code> to keep data in sync.</p>
</li>
<li><p>You only need to maintain a single source of truth, which is the <code>URL</code>.</p>
</li>
<li><p>You have less code, which is easier to maintain.</p>
</li>
</ul>
<h3 id="heading-how-to-derive-state-from-external-data">How to Derive State From External Data</h3>
<p>Data fetching libraries like React Query provide states that can be used as a single source of truth. Saving this data in <code>useState</code> can sometimes be redundant.</p>
<p>Look at this example using React Query. First, create a parent component that will render the user details:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { useSearchParams } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-router"</span>;
<span class="hljs-keyword">import</span> UserDetail <span class="hljs-keyword">from</span> <span class="hljs-string">"./user-detail"</span>;

<span class="hljs-keyword">const</span> UserIdInput = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> [search, updateSearch] = useSearchParams();

  <span class="hljs-keyword">return</span> (
    &lt;input
      value={search.get(<span class="hljs-string">"id"</span>) || <span class="hljs-string">""</span>}
      onChange={<span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> updateSearch({ id: e.target.value })}
    /&gt;
  );
};

<span class="hljs-keyword">const</span> User = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">return</span> (
    &lt;&gt;
      &lt;UserIdInput /&gt;
      &lt;UserDetail /&gt;
    &lt;/&gt;
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> User;
</code></pre>
<p>You use the <code>&lt;UserIdInput /&gt;</code> to update the user details you need to get. Now create the <code>&lt;UserDetail /&gt;</code> component:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { useQuery } <span class="hljs-keyword">from</span> <span class="hljs-string">"@tanstack/react-query"</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> { useSearchParams } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-router"</span>;

<span class="hljs-keyword">interface</span> IUser {
  id: <span class="hljs-built_in">number</span>;
  name: <span class="hljs-built_in">string</span>;
}

<span class="hljs-keyword">const</span> getUser = <span class="hljs-keyword">async</span> (id: <span class="hljs-built_in">string</span>) =&gt; {
  <span class="hljs-keyword">const</span> req = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">`https://jsonplaceholder.typicode.com/users/<span class="hljs-subst">${id}</span>`</span>);
  <span class="hljs-keyword">await</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function">(<span class="hljs-params">r</span>) =&gt;</span> <span class="hljs-built_in">setTimeout</span>(r, <span class="hljs-number">2</span>_000));
  <span class="hljs-keyword">return</span> req.json();
};

<span class="hljs-keyword">const</span> UserDetail = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> [search] = useSearchParams();
  <span class="hljs-keyword">const</span> userId = search.get(<span class="hljs-string">"id"</span>) || <span class="hljs-string">""</span>;

  <span class="hljs-keyword">const</span> {
    data,
    isFetching,
    error: fError,
  } = useQuery&lt;IUser&gt;({
    queryKey: [<span class="hljs-string">"user"</span>, userId],
    queryFn: <span class="hljs-function">() =&gt;</span> getUser(userId),
    enabled: <span class="hljs-built_in">Boolean</span>(userId),
    refetchOnWindowFocus: <span class="hljs-literal">false</span>,
  });

  <span class="hljs-keyword">const</span> [user, setUser] = useState&lt;IUser&gt;();
  <span class="hljs-keyword">const</span> [error, setError] = useState&lt;<span class="hljs-built_in">string</span>&gt;();
  <span class="hljs-keyword">const</span> [loading, setLoading] = useState(<span class="hljs-literal">true</span>);

  useEffect(<span class="hljs-function">() =&gt;</span> {
    setUser(<span class="hljs-literal">undefined</span>);
    setError(<span class="hljs-literal">undefined</span>);
  }, [userId]);

  useEffect(<span class="hljs-function">() =&gt;</span> {
    setError(fError?.message);
    setLoading(isFetching);
    setUser(data);
  }, [data, fError, isFetching]);

  <span class="hljs-built_in">console</span>.count(<span class="hljs-string">"__ RENDERED __"</span>);

  <span class="hljs-built_in">console</span>.log({ data, user, isFetching, loading, error });

  <span class="hljs-keyword">if</span> (error) <span class="hljs-keyword">return</span> &lt;div&gt;Try again later!&lt;/div&gt;;
  <span class="hljs-keyword">if</span> (loading) <span class="hljs-keyword">return</span> &lt;div&gt;Loading...&lt;/div&gt;;

  <span class="hljs-keyword">if</span> (user) {
    <span class="hljs-keyword">return</span> (
      &lt;div&gt;
        &lt;p style={{ fontSize: <span class="hljs-string">"2rem"</span> }}&gt;
          {user.id}: {user.name}
        &lt;/p&gt;
      &lt;/div&gt;
    );
  }

  <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> UserDetail;
</code></pre>
<p>The <code>&lt;UserDetail /&gt;</code> component renders the details of a user. It gets the user’s ID from the URL.</p>
<p>The component uses the <code>getUser</code> function to get dummy data from an API. It simulates a little network delay by waiting for an extra two seconds with this line of code:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">await</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function">(<span class="hljs-params">r</span>) =&gt;</span> <span class="hljs-built_in">setTimeout</span>(r, <span class="hljs-number">2</span>_000));
</code></pre>
<p>The component uses <code>useQuery</code> to fetch the data. Internally, part of the state React Query keeps track of is the <code>data</code>, <code>isFetching</code>, and <code>error</code>. But the component creates another local state to keep track of these React Query states.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762629782249/ac64794f-9264-4e31-989c-5ee1a7274b0e.gif" alt="ac64794f-9264-4e31-989c-5ee1a7274b0e" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>Notice that the component renders a total of four times. The component re-renders when React Query and local states change. Also, notice that both states are out of sync at some point. For example, in the third log, the <code>data</code> key from React Query already had the user details, while the local <code>user</code> state is still undefined. You had to use <code>useEffect</code> to update its state.</p>
<p>It’s more interesting when the component tries to get another user’s details.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762630953734/d1810dfd-82d9-4c6d-9c57-fa473f6438e4.gif" alt="d1810dfd-82d9-4c6d-9c57-fa473f6438e4" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>The component reacts to when the user’s ID changes, when React Query state changes, and when local state changes. Similar to the mount problem, the component re-renders more than it needs to: it re-renders six times. Also, the local state was out of sync at some point because we had to rely on <code>useEffect</code>.</p>
<h4 id="heading-derive-directly-from-react-query">Derive Directly From React Query</h4>
<p>You can correct all these issues by using a derived state like this:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { useQuery } <span class="hljs-keyword">from</span> <span class="hljs-string">"@tanstack/react-query"</span>;
<span class="hljs-keyword">import</span> { useSearchParams } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-router"</span>;

<span class="hljs-keyword">interface</span> IUser {
  id: <span class="hljs-built_in">number</span>;
  name: <span class="hljs-built_in">string</span>;
}

<span class="hljs-keyword">const</span> getUser = <span class="hljs-keyword">async</span> (id: <span class="hljs-built_in">string</span>) =&gt; {
  <span class="hljs-keyword">const</span> req = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">`https://jsonplaceholder.typicode.com/users/<span class="hljs-subst">${id}</span>`</span>);
  <span class="hljs-keyword">await</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function">(<span class="hljs-params">r</span>) =&gt;</span> <span class="hljs-built_in">setTimeout</span>(r, <span class="hljs-number">2</span>_000));
  <span class="hljs-keyword">return</span> req.json();
};

<span class="hljs-keyword">const</span> UserDetail = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> [search] = useSearchParams();
  <span class="hljs-keyword">const</span> userId = search.get(<span class="hljs-string">"id"</span>) || <span class="hljs-string">""</span>;

  <span class="hljs-keyword">const</span> {
    data: user,
    isFetching: loading,
    error,
  } = useQuery&lt;IUser&gt;({
    queryKey: [<span class="hljs-string">"user"</span>, userId],
    queryFn: <span class="hljs-function">() =&gt;</span> getUser(userId),
    enabled: <span class="hljs-built_in">Boolean</span>(userId),
  });

  <span class="hljs-built_in">console</span>.count(<span class="hljs-string">"__ RENDERED __"</span>);

  <span class="hljs-keyword">if</span> (error) <span class="hljs-keyword">return</span> &lt;div&gt;Try again later!&lt;/div&gt;;
  <span class="hljs-keyword">if</span> (loading) <span class="hljs-keyword">return</span> &lt;div&gt;Loading...&lt;/div&gt;;

  <span class="hljs-keyword">if</span> (user) {
    <span class="hljs-keyword">return</span> (
      &lt;div&gt;
        &lt;p style={{ fontSize: <span class="hljs-string">"2rem"</span> }}&gt;
          {user.id}: {user.name}
        &lt;/p&gt;
      &lt;/div&gt;
    );
  }

  <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> UserDetail;
</code></pre>
<p>React Query is now the single source of truth. There is no more manual synchronisation or extra <code>useState</code>s.</p>
<p>Also, the first thing you will notice is that you have fewer lines of code. This makes it easier to maintain. Check the GIF below to see how often the component renders when it mounts.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762631232781/d2b03b52-bffe-4226-9535-5b8d5a4eca20.gif" alt="d2b03b52-bffe-4226-9535-5b8d5a4eca20" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>As you can see, the component re-renders only twice. Once, when the component initially mounts, and again when React Query state changes.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762631500289/e87f1c5e-2741-4c2a-bf1d-9406f06812ce.gif" alt="e87f1c5e-2741-4c2a-bf1d-9406f06812ce" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>The same thing happened when you got another user's details. You have fewer re-renders: three times as opposed to six times when we kept track of the state locally.</p>
<h2 id="heading-how-to-prevent-recalculation-of-a-derived-state">How to Prevent Recalculation of a Derived State</h2>
<p>Most calculations are fast enough to run on every render. This becomes a problem when it’s an expensive calculation. In such a case, you an use <code>useMemo</code> and/or <code>memo</code> to avoid unnecessary work.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> Detail = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> product = useQuery(...);
  <span class="hljs-keyword">const</span> users = useQuery(...);

  <span class="hljs-keyword">const</span> result = useMemo(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> expensiveResult = ...;

    <span class="hljs-keyword">return</span> expensiveResult;
  }, [product.data]);

  <span class="hljs-keyword">return</span> (
    &lt;&gt;
      {<span class="hljs-comment">/* some other components */</span>}
      &lt;Result result={result} /&gt;
    &lt;/&gt;
  );
};

<span class="hljs-keyword">const</span> Result = memo(<span class="hljs-function">(<span class="hljs-params">{ result }: { result: <span class="hljs-built_in">number</span> }</span>) =&gt;</span> {
  <span class="hljs-keyword">return</span> &lt;&gt;&lt;/&gt;;
});
</code></pre>
<p>With <code>useMemo</code>, the <code>result</code> variable will be recalculated only when <code>product.data</code> changes. This means that the <code>&lt;Result /&gt;</code> component remains the same until <code>product.data</code> changes.</p>
<p>You can read more here about <a target="_blank" href="https://www.freecodecamp.org/news/how-to-work-with-usememo-in-react/">how to use <code>useMemo</code> in React</a>.</p>
<h2 id="heading-when-to-use-usestate">When to Use <code>useState</code></h2>
<p>While the article has focused on using derived states, there are cases where you must use <code>useState</code>.</p>
<h3 id="heading-controlled-input">Controlled Input</h3>
<p>You need <code>useState</code> to manage the input’s value and keep it in sync with the component’s state when building a controlled input.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { useState, <span class="hljs-keyword">type</span> FormEventHandler } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

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

  <span class="hljs-keyword">const</span> handleSubmit: FormEventHandler&lt;HTMLFormElement&gt; = <span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> {
    e.preventDefault();
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Submitted value:"</span>, username);
  };

  <span class="hljs-keyword">return</span> (
    &lt;form
      onSubmit={handleSubmit}
      style={{ display: <span class="hljs-string">"flex"</span>, flexDirection: <span class="hljs-string">"column"</span>, gap: <span class="hljs-string">"1rem"</span> }}
    &gt;
      &lt;div&gt;
        &lt;label htmlFor=<span class="hljs-string">"username"</span>&gt;Username:&lt;/label&gt;
        &lt;input
          id=<span class="hljs-string">"username"</span>
          <span class="hljs-keyword">type</span>=<span class="hljs-string">"text"</span>
          value={username}
          onChange={<span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> setUsername(e.target.value)}
          style={{
            marginLeft: <span class="hljs-string">"1rem"</span>,
            padding: <span class="hljs-string">"0.5rem 0.4rem"</span>,
            border: <span class="hljs-string">`1px solid <span class="hljs-subst">${username.length &lt; <span class="hljs-number">2</span> ? <span class="hljs-string">"red"</span> : <span class="hljs-string">"green"</span>}</span>`</span>,
          }}
        /&gt;
      &lt;/div&gt;
      &lt;button <span class="hljs-keyword">type</span>=<span class="hljs-string">"submit"</span>&gt;Submit&lt;/button&gt;
    &lt;/form&gt;
  );
};
</code></pre>
<p><code>useState</code> is needed here because:</p>
<ul>
<li><p>you want to track the user’s value as they type</p>
</li>
<li><p>the value comes directly from the user interaction</p>
</li>
</ul>
<p>Because we are tracking the input value with <code>useState</code>, we can easily validate the <code>username</code> and change the border’s color. freeCodeCamp has an <a target="_blank" href="https://www.freecodecamp.org/news/what-are-controlled-and-uncontrolled-components-in-react/">article that explains what controlled inputs are.</a></p>
<h3 id="heading-independent-state-changes">Independent State Changes</h3>
<p>You should use <code>useState</code> when a value can change without depending on other state or props. For example, when toggling a modal, you need <code>useState</code> to keep track of its state.</p>
<pre><code class="lang-typescript"><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> Modal = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> [isModalOpen, setIsModalOpen] = useState(<span class="hljs-literal">false</span>);

  <span class="hljs-keyword">return</span> (
    &lt;div&gt;
      &lt;button onClick={<span class="hljs-function">() =&gt;</span> setIsModalOpen(<span class="hljs-literal">true</span>)}&gt;Open Modal&lt;/button&gt;
      {isModalOpen &amp;&amp; (
        &lt;div&gt;
          &lt;p&gt;Modal Content&lt;/p&gt;
          &lt;button onClick={<span class="hljs-function">() =&gt;</span> setIsModalOpen(<span class="hljs-literal">false</span>)}&gt;Close&lt;/button&gt;
        &lt;/div&gt;
      )}
    &lt;/div&gt;
  );
};
</code></pre>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Managing state is one of the trickiest parts of React. You shouldn’t store what you can calculate, and you should only store what you can’t derive.</p>
<p>By keeping states minimal and deriving when possible, it will be easier to debug and maintain your components.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build a Reusable useSearch Hook in React ]]>
                </title>
                <description>
                    <![CDATA[ Recently, I needed to add a search feature to a React app. Naturally, I did what many developers would do—I turned to Google for help. The first article I found was about building a search and filter component in React. As I read through it, I couldn... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-build-a-reusable-usesearch-hook-in-react/</link>
                <guid isPermaLink="false">67be32ff803613c5edf10387</guid>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ ReactHooks ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Spruce Emmanuel ]]>
                </dc:creator>
                <pubDate>Tue, 25 Feb 2025 21:15:43 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1740494925672/3a87e5a2-5233-4fae-a652-4fbf5b325ded.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Recently, I needed to add a search feature to a React app. Naturally, I did what many developers would do—I turned to Google for help.</p>
<p>The first article I found was about building a search and filter component in React. As I read through it, I couldn't help but think, <em>This is okay, but it misses so many important cases.</em> Then it hit me—I was the one who wrote that article a few years ago.</p>
<p>Turns out, my past self had some learning to do.</p>
<p>Since then, I've tackled more complex projects and realized that search in React can be so much more powerful, flexible, and efficient. That's why I've developed a reusable useSearch hook that handles everything from large datasets to typo-tolerant searches—and I'm excited to share it with you.</p>
<p>In this article, I'll walk you through building it step by step. By the end, you'll have a high-performance search system that you can drop into any React project, no matter how complex your data gets.</p>
<h2 id="heading-outline">Outline</h2>
<ul>
<li><p><a class="post-section-overview" href="#introduction">Introduction</a></p>
</li>
<li><p><a class="post-section-overview" href="#the-problem-with-simple-search-implementations">The Problem With Simple Search Implementations</a></p>
</li>
<li><p><a class="post-section-overview" href="#how-to-build-a-reusable-usesearch-hook">How to Build a Reusable useSearch Hook</a></p>
</li>
<li><p><a class="post-section-overview" href="#how-to-create-the-filters">How to Create the Filters</a></p>
</li>
<li><p><a class="post-section-overview" href="#how-to-handle-typos-in-search">How to Handle Typos in Search</a></p>
</li>
<li><p><a class="post-section-overview" href="#how-to-use-the-ready-made-usesearch-hook">How to Use the Ready-Made useSearch Hook</a></p>
</li>
<li><p><a class="post-section-overview" href="#conclusion">Conclusion</a></p>
</li>
</ul>
<h3 id="heading-who-should-read-this">Who Should Read This?</h3>
<p>If you’re a React developer, whether you're just getting started or have plenty of experience, you’ve probably run into the limits of basic search features. Maybe your search is sluggish with large datasets, struggles with typos, or isn’t flexible enough to handle different data structures. If that sounds familiar, this guide is for you. We’ll build a high-performance, reusable search system that actually works in real-world apps.</p>
<h3 id="heading-what-youll-learn">What You’ll Learn</h3>
<p>By the end of this guide, you’ll know how to:</p>
<ul>
<li><p>Spot the common pitfalls of simple search implementations.</p>
</li>
<li><p>Build a powerful <code>useSearch</code> hook that works with different data types and nested objects.</p>
</li>
<li><p>Optimize performance with techniques like debouncing and memoization.</p>
</li>
<li><p>Improve the user experience with fuzzy search that handles typos.</p>
</li>
<li><p>Implement pagination to efficiently manage large result sets.</p>
</li>
</ul>
<h3 id="heading-prerequisites">Prerequisites</h3>
<p>Before diving in, you should be comfortable with:</p>
<ul>
<li><p>React and JavaScript fundamentals.</p>
</li>
<li><p>Basic React hooks such as <code>useState</code> and <code>useEffect</code>.</p>
</li>
<li><p>Working with arrays and objects in JavaScript.</p>
</li>
</ul>
<h2 id="heading-the-problem-with-simple-search-implementations">The Problem With Simple Search Implementations</h2>
<p>Let’s start with a basic search component:</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">SimpleSearch</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">const</span> data = [
        { <span class="hljs-attr">name</span>: <span class="hljs-string">"JavaScript"</span> },
        { <span class="hljs-attr">name</span>: <span class="hljs-string">"Python"</span> },
        { <span class="hljs-attr">name</span>: <span class="hljs-string">"Java"</span> }
    ];

    <span class="hljs-keyword">const</span> [query, setQuery] = useState(<span class="hljs-string">""</span>);

    <span class="hljs-keyword">const</span> results = data.filter(<span class="hljs-function">(<span class="hljs-params">item</span>) =&gt;</span> item.name.includes(query));

    <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">input</span>
                <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span>
                <span class="hljs-attr">value</span>=<span class="hljs-string">{query}</span>
                <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setQuery(e.target.value)}
                placeholder="Search..."
            /&gt;
            <span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
                {results.map((item, 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>&gt;</span>{item.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 class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
    );
}
</code></pre>
<div class="embed-wrapper">
        <iframe width="100%" height="350" src="https://codepen.io/Spruce_khalifa/embed/NPKJyyR" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="CodePen embed" scrolling="no" allowtransparency="true" allowfullscreen="true" loading="lazy"></iframe></div>
<p> </p>
<p>At first glance, this works fine: you type a query and get matching results. But in real-world applications, search needs to handle much more than just simple string comparisons. Here are some major limitations:</p>
<ul>
<li><p><strong>Limited data support:</strong> This approach only works with plain strings, making it impractical for complex data structures.</p>
</li>
<li><p><strong>No support for nested objects:</strong> If your data has deeper structures (for example, <code>{ user: { name: "JavaScript" } }</code>), this won’t work.</p>
</li>
<li><p><strong>No typo tolerance:</strong> A slight misspelling like <code>"javascrpt"</code> won’t match <code>"JavaScript"</code>, which can frustrate users.</p>
</li>
<li><p><strong>Performance bottlenecks:</strong> Every keystroke triggers a full re-render, which can cause lag, especially with large datasets.</p>
</li>
</ul>
<p>Clearly, we need something more powerful. Let’s build a better search system that’s flexible, optimized, and user-friendly.</p>
<h2 id="heading-how-to-build-a-reusable-usesearch-hook">How to Build a Reusable <code>useSearch</code> Hook</h2>
<p>To overcome these issues, we’ll build a reusable <code>useSearch</code> hook that:</p>
<ul>
<li><p>Supports multiple data types (strings, numbers, dates, nested objects).</p>
</li>
<li><p>Improves performance using debouncing and memoization.</p>
</li>
<li><p>Handles typos with fuzzy search.</p>
</li>
</ul>
<h3 id="heading-how-to-create-the-hook">How to Create the Hook</h3>
<p>Let’s start by creating the hook. It takes in data, the search query, and a list of filter functions to apply:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// hooks/useSearch.js</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">useSearch</span>(<span class="hljs-params">data, query, ...filters</span>) </span>{
    <span class="hljs-keyword">const</span> debouncedQuery = useDebounce(query, <span class="hljs-number">300</span>);

    <span class="hljs-keyword">return</span> React.useMemo(<span class="hljs-function">() =&gt;</span> {
        <span class="hljs-keyword">const</span> dataArray = <span class="hljs-built_in">Array</span>.isArray(data) ? data : [data];

        <span class="hljs-keyword">try</span> {
            <span class="hljs-comment">// Apply each filter function in sequence</span>
            <span class="hljs-keyword">return</span> filters.reduce(
                <span class="hljs-function">(<span class="hljs-params">acc, feature</span>) =&gt;</span> feature(acc, debouncedQuery),
                dataArray
            );
        } <span class="hljs-keyword">catch</span> (error) {
            <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Error applying search features:"</span>, error);
            <span class="hljs-keyword">return</span> dataArray;
        }
    }, [data, debouncedQuery, filters]);
}
</code></pre>
<h3 id="heading-how-to-handle-the-query-with-usedebounce">How to Handle the Query with <code>useDebounce</code></h3>
<p>Without debouncing, every single keystroke triggers a new search. Imagine typing <code>"apple"</code>—each letter (<code>a</code>, <code>p</code>, <code>p</code>, <code>l</code>, <code>e</code>) fires a search request, causing multiple re-renders and potential performance issues.</p>
<p>To fix this, we used a debounce mechanism in the <code>useSearch</code> hook that waits until the user stops typing before running the search. Here’s what the <code>useDebounce</code> hook looks like:</p>
<pre><code class="lang-javascript"><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">useDebounce</span>(<span class="hljs-params">value, delay</span>) </span>{
    <span class="hljs-keyword">const</span> [debouncedValue, setDebouncedValue] = React.useState(value);

    React.useEffect(<span class="hljs-function">() =&gt;</span> {
        <span class="hljs-keyword">const</span> timeoutId = <span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">() =&gt;</span> {
            setDebouncedValue(value);
        }, delay);

        <span class="hljs-keyword">return</span> <span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">clearTimeout</span>(timeoutId);
    }, [value, delay]);

    <span class="hljs-keyword">return</span> debouncedValue;
}
</code></pre>
<p>This hook ensures that the search only triggers after 300ms of inactivity, preventing unnecessary re-renders and improving responsiveness.</p>
<p>Want to see the difference in action? Compare a debounced search to one that updates on every keystroke in the demo below:</p>
<div class="embed-wrapper">
        <iframe width="100%" height="350" src="https://codepen.io/Spruce_khalifa/embed/pvzYaXp" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="CodePen embed" scrolling="no" allowtransparency="true" allowfullscreen="true" loading="lazy"></iframe></div>
<p> </p>
<h3 id="heading-how-to-optimize-performance-with-reactusememo">How to Optimize Performance with <code>React.useMemo</code></h3>
<p>Filtering large datasets can be expensive, and if our search logic runs every time a component re-renders—even when the search query hasn’t changed—it can slow things down. That’s where <code>React.useMemo()</code> comes in.</p>
<p>By wrapping our search logic in <code>useMemo</code>, we ensure it only recalculates when the search query, filters, or data actually change:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">return</span> React.useMemo(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-comment">// Filtering logic</span>
}, [data, debouncedQuery, filters]);
</code></pre>
<p>But how much of a difference does this make? Imagine a parent component with an unrelated state (like a counter). Every time the parent re-renders, a non-memoized search would still run, even if the query remains the same.</p>
<p>The live demo below compares two search implementations, one without <code>useMemo</code> and one with it. Try changing an unrelated state in the parent and see how many times each search runs:</p>
<div class="embed-wrapper">
        <iframe width="100%" height="350" src="https://codepen.io/Spruce_khalifa/embed/EaYMEar" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="CodePen embed" scrolling="no" allowtransparency="true" allowfullscreen="true" loading="lazy"></iframe></div>
<p> </p>
<p>With <code>useMemo</code>, the search logic only runs when the query, filters, or data change, keeping performance smooth and avoiding unnecessary computations.</p>
<h3 id="heading-how-to-chain-filters-with-reduce">How to Chain Filters with <code>.reduce()</code></h3>
<p>The hook uses <code>.reduce()</code> to sequentially apply each filter function to the data, keeping the logic clean and modular:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">return</span> filters.reduce(
    <span class="hljs-function">(<span class="hljs-params">acc, feature</span>) =&gt;</span> feature(acc, debouncedQuery),
    dataArray
);
</code></pre>
<p>This approach makes it easy to add or remove filters as needed.</p>
<h2 id="heading-how-to-create-the-filters">How to Create the Filters</h2>
<p>Filters add the magic to our search hook by processing the data based on the search query. For this project, I created two filters: one for searching and one for pagination.</p>
<h3 id="heading-1-the-search-filter">1. The Search Filter</h3>
<p>The search filter checks specified fields in an object for matches with the query. It supports several matching strategies (exact, startsWith, endsWith, contains):</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// utils/search.js</span>

<span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">search</span>(<span class="hljs-params">options</span>) </span>{
    <span class="hljs-keyword">const</span> { fields, matchType } = options;

    <span class="hljs-keyword">return</span> <span class="hljs-function">(<span class="hljs-params">data, query</span>) =&gt;</span> {
        <span class="hljs-keyword">const</span> trimmedQuery = <span class="hljs-built_in">String</span>(query).trim().toLowerCase();

        <span class="hljs-keyword">if</span> (!trimmedQuery) <span class="hljs-keyword">return</span> data;

        <span class="hljs-keyword">return</span> data.filter(<span class="hljs-function">(<span class="hljs-params">item</span>) =&gt;</span> {
            <span class="hljs-keyword">const</span> fieldsArray = fields
                ? <span class="hljs-built_in">Array</span>.isArray(fields)
                    ? fields
                    : [fields]
                : getAllKeys(item);

            <span class="hljs-keyword">return</span> fieldsArray.some(<span class="hljs-function">(<span class="hljs-params">field</span>) =&gt;</span> {
                <span class="hljs-keyword">const</span> fieldValue = getFieldValue(item, field);
                <span class="hljs-keyword">if</span> (fieldValue == <span class="hljs-literal">null</span>) <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;

                <span class="hljs-keyword">const</span> stringValue = convertToString(fieldValue).toLowerCase();

                <span class="hljs-keyword">switch</span> (matchType) {
                    <span class="hljs-keyword">case</span> <span class="hljs-string">"exact"</span>:
                        <span class="hljs-keyword">return</span> stringValue === trimmedQuery;
                    <span class="hljs-keyword">case</span> <span class="hljs-string">"startsWith"</span>:
                        <span class="hljs-keyword">return</span> stringValue.startsWith(trimmedQuery);
                    <span class="hljs-keyword">case</span> <span class="hljs-string">"endsWith"</span>:
                        <span class="hljs-keyword">return</span> stringValue.endsWith(trimmedQuery);
                    <span class="hljs-keyword">case</span> <span class="hljs-string">"contains"</span>:
                        <span class="hljs-keyword">return</span> stringValue.includes(trimmedQuery);
                    <span class="hljs-keyword">default</span>:
                        <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">`Unsupported match type: <span class="hljs-subst">${matchType}</span>`</span>);
                }
            });
        });
    };
}
</code></pre>
<p>Let’s go through it to see how it works:</p>
<ol>
<li><p>Cleaning up the query:</p>
<pre><code class="lang-javascript"> <span class="hljs-keyword">const</span> trimmedQuery = <span class="hljs-built_in">String</span>(query).trim().toLowerCase();

 <span class="hljs-keyword">if</span> (!trimmedQuery) {
     <span class="hljs-keyword">return</span> data;
 }
</code></pre>
<p> This makes the search case-insensitive and removes extra spaces.</p>
</li>
<li><p>Determining fields to search:</p>
<pre><code class="lang-javascript"> <span class="hljs-keyword">const</span> fieldsArray = fields
     ? <span class="hljs-built_in">Array</span>.isArray(fields)
         ? fields
         : [fields]
     : getAllKeys(item);
</code></pre>
<p> If specific fields aren’t provided, it extracts all keys, including nested ones.</p>
</li>
<li><p>Filtering the data:</p>
<pre><code class="lang-javascript"> <span class="hljs-keyword">return</span> fieldsArray.some(<span class="hljs-function">(<span class="hljs-params">field</span>) =&gt;</span> {
     <span class="hljs-keyword">const</span> fieldValue = getFieldValue(item, field);

     <span class="hljs-keyword">if</span> (fieldValue == <span class="hljs-literal">null</span>) {
         <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
     }

     <span class="hljs-keyword">const</span> stringValue = convertToString(fieldValue).toLowerCase();

     <span class="hljs-comment">// Matching logic based on matchType follows...</span>
 });
</code></pre>
</li>
</ol>
<h3 id="heading-2-the-helper-functions">2. The Helper Functions</h3>
<p>To keep our filtering logic clean and focused, we use a few helper functions. These functions handle common tasks like retrieving keys from an object, getting nested field values, and converting values to strings. This way, our search filter can work with a variety of data structures and types without cluttering the main logic.</p>
<ul>
<li><p>Extracting all keys with <code>getAllKeys</code>:</p>
<p>  The <code>getAllKeys</code> function scans an object to gather all its keys—even those nested within arrays or sub-objects. If you don't provide specific fields for searching, this function ensures that every potential field is considered.</p>
<pre><code class="lang-javascript">  <span class="hljs-comment">// utils/getAllKeys.js</span>

  <span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getAllKeys</span>(<span class="hljs-params">item, prefix = <span class="hljs-string">""</span></span>) </span>{
      <span class="hljs-keyword">if</span> (!item || <span class="hljs-keyword">typeof</span> item !== <span class="hljs-string">"object"</span>) {
          <span class="hljs-keyword">return</span> [];
      }

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

      <span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> key <span class="hljs-keyword">of</span> <span class="hljs-built_in">Object</span>.keys(item)) {
          <span class="hljs-keyword">const</span> value = item[key];
          <span class="hljs-keyword">const</span> fieldPath = prefix ? <span class="hljs-string">`<span class="hljs-subst">${prefix}</span>.<span class="hljs-subst">${key}</span>`</span> : key;

          <span class="hljs-keyword">if</span> (<span class="hljs-built_in">Array</span>.isArray(value)) {
              value.forEach(<span class="hljs-function">(<span class="hljs-params">arrayItem, index</span>) =&gt;</span> {
                  <span class="hljs-keyword">if</span> (
                      arrayItem &amp;&amp;
                      <span class="hljs-keyword">typeof</span> arrayItem === <span class="hljs-string">"object"</span> &amp;&amp;
                      !(arrayItem <span class="hljs-keyword">instanceof</span> <span class="hljs-built_in">Date</span>)
                  ) {
                      fields.push(...getAllKeys(arrayItem, <span class="hljs-string">`<span class="hljs-subst">${fieldPath}</span>[<span class="hljs-subst">${index}</span>]`</span>));
                  } <span class="hljs-keyword">else</span> {
                      fields.push(<span class="hljs-string">`<span class="hljs-subst">${fieldPath}</span>[<span class="hljs-subst">${index}</span>]`</span>);
                  }
              });
          } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (value <span class="hljs-keyword">instanceof</span> <span class="hljs-built_in">Date</span>) {
              fields.push(fieldPath);
          } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (value &amp;&amp; <span class="hljs-keyword">typeof</span> value === <span class="hljs-string">"object"</span>) {
              fields.push(...getAllKeys(value, fieldPath));
          } <span class="hljs-keyword">else</span> {
              fields.push(fieldPath);
          }
      }

      <span class="hljs-keyword">return</span> fields;
  }
</code></pre>
</li>
<li><p>Retrieving field values with <code>getFieldValue</code>:</p>
<p>  The <code>getFieldValue</code> function extracts the value of a given field from an object using a path string (like <code>"</code><a target="_blank" href="http://user.name"><code>user.name</code></a><code>"</code> or <code>"items[0].title"</code>). It splits the path into individual keys and then traverses the object step by step to find the correct value.</p>
<pre><code class="lang-javascript">  <span class="hljs-comment">// utils/getFieldValue.js</span>

  <span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getFieldValue</span>(<span class="hljs-params">item, field</span>) </span>{
      <span class="hljs-keyword">const</span> keys = field.split(<span class="hljs-regexp">/[\.\[\]]/</span>).filter(<span class="hljs-built_in">Boolean</span>);
      <span class="hljs-keyword">let</span> value = item;

      <span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> key <span class="hljs-keyword">of</span> keys) {
          <span class="hljs-keyword">if</span> (value == <span class="hljs-literal">null</span>) {
              <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;
          }
          value = value[key];
      }

      <span class="hljs-keyword">return</span> value;
  }
</code></pre>
</li>
<li><p>Converting values to strings with <code>convertToString</code>:</p>
<p>  For our search comparisons, we need to ensure all data is in string format. The <code>convertToString</code> function handles this conversion. It turns dates into ISO strings and booleans into <code>"true"</code> or <code>"false"</code>, ensuring a uniform format for our search filter.</p>
<pre><code class="lang-javascript">  <span class="hljs-comment">// utils/convertToString.js</span>

  <span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">convertToString</span>(<span class="hljs-params">value</span>) </span>{
      <span class="hljs-keyword">if</span> (value <span class="hljs-keyword">instanceof</span> <span class="hljs-built_in">Date</span>) {
          <span class="hljs-keyword">return</span> value.toISOString();
      }

      <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> value === <span class="hljs-string">"boolean"</span>) {
          <span class="hljs-keyword">return</span> value ? <span class="hljs-string">"true"</span> : <span class="hljs-string">"false"</span>;
      }

      <span class="hljs-keyword">return</span> <span class="hljs-built_in">String</span>(value);
  }
</code></pre>
</li>
</ul>
<h3 id="heading-3-the-pagination-filter">3. The Pagination Filter</h3>
<p>For large datasets, displaying all results at once isn't practical. The pagination filter helps by returning only a subset of the data based on the current page and the number of items per page. This not only improves performance but also makes the data more manageable for users.</p>
<p>In this function, we calculate the starting index by using the current page number and page size. Then, we use the JavaScript <code>slice</code> method to pick out only the items that belong to that specific page. Although the query parameter is present, it isn’t used here—it’s just for keeping the hook's interface consistent.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// utils/paginate.js</span>

<span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">paginate</span>(<span class="hljs-params">options</span>) </span>{
    <span class="hljs-keyword">const</span> { page = <span class="hljs-number">1</span>, pageSize = <span class="hljs-number">10</span> } = options;

    <span class="hljs-keyword">return</span> <span class="hljs-function">(<span class="hljs-params">data, query</span>) =&gt;</span> {
        <span class="hljs-comment">// Query is not used here; it’s only for compatibility with our hook.</span>
        <span class="hljs-keyword">const</span> startIndex = (page - <span class="hljs-number">1</span>) * pageSize;

        <span class="hljs-keyword">return</span> data.slice(startIndex, startIndex + pageSize);
    };
}
</code></pre>
<p>In this code, the pagination filter efficiently slices the data array, so you only get the subset of results that you want to display on the current page.</p>
<h2 id="heading-how-to-use-the-hook-with-search-and-pagination-filters">How to Use the Hook with Search and Pagination Filters</h2>
<p>Now that we have both the search and pagination filters set up, let’s see how to use them in a React component.</p>
<p>First, import the custom <code>useSearch</code> hook and the filter functions:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> useSearch <span class="hljs-keyword">from</span> <span class="hljs-string">"./hooks/useSearch.js"</span>;
<span class="hljs-keyword">import</span> search <span class="hljs-keyword">from</span> <span class="hljs-string">"./utils/search.js"</span>;
<span class="hljs-keyword">import</span> paginate <span class="hljs-keyword">from</span> <span class="hljs-string">"./utils/paginate.js"</span>;
</code></pre>
<p>Next, create a component that uses these filters. In this example, we have an array of items, and we want to search by name and display a fixed number of results per page. We also reset to the first page whenever a new search query is entered.</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">SearchComponent</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-comment">// Example data array</span>
    <span class="hljs-keyword">const</span> data = [
        { <span class="hljs-attr">name</span>: <span class="hljs-string">"JavaScript"</span> },
        { <span class="hljs-attr">name</span>: <span class="hljs-string">"Python"</span> },
        { <span class="hljs-attr">name</span>: <span class="hljs-string">"Java"</span> },
        { <span class="hljs-attr">name</span>: <span class="hljs-string">"Ruby"</span> },
        <span class="hljs-comment">// Imagine more data here</span>
    ];

    <span class="hljs-keyword">const</span> [query, setQuery] = React.useState(<span class="hljs-string">""</span>);
    <span class="hljs-keyword">const</span> [page, setPage] = React.useState(<span class="hljs-number">1</span>);
    <span class="hljs-keyword">const</span> pageSize = <span class="hljs-number">3</span>; <span class="hljs-comment">// Items per page</span>

    <span class="hljs-comment">// Apply both search and pagination filters with our custom hook.</span>
    <span class="hljs-keyword">const</span> results = useSearch(
        data,
        query,
        search({
            <span class="hljs-attr">fields</span>: [<span class="hljs-string">"name"</span>],
            <span class="hljs-attr">matchType</span>: <span class="hljs-string">"contains"</span>, <span class="hljs-comment">// Options: "exact", "startsWith", etc.</span>
        }),
        paginate({ page, pageSize })
    );

    <span class="hljs-comment">// Compute total pages based on filtered results (without pagination)</span>
    <span class="hljs-keyword">const</span> filteredData = search({ <span class="hljs-attr">fields</span>: [<span class="hljs-string">"name"</span>], <span class="hljs-attr">matchType</span>: <span class="hljs-string">"contains"</span> })(
        data,
        query
    );

    <span class="hljs-keyword">const</span> totalPages = <span class="hljs-built_in">Math</span>.ceil(filteredData.length / pageSize);

    <span class="hljs-keyword">return</span> (
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">padding:</span> "<span class="hljs-attr">20px</span>", <span class="hljs-attr">fontFamily:</span> "<span class="hljs-attr">Arial</span>, <span class="hljs-attr">sans-serif</span>" }}&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Search and Pagination<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
                <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span>
                <span class="hljs-attr">value</span>=<span class="hljs-string">{query}</span>
                <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> {
                    setQuery(e.target.value);
                    setPage(1); // Reset to first page on new search
                }}
                placeholder="Search by name..."
                style={{ padding: "8px", width: "300px", marginBottom: "10px" }}
            /&gt;
            <span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
                {results.map((item, 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>&gt;</span>{item.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 class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">marginTop:</span> "<span class="hljs-attr">10px</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> setPage((prev) =&gt; Math.max(prev - 1, 1))}
                    disabled={page === 1}
                    style={{ padding: "6px 12px", marginRight: "10px" }}
                &gt;
                    Previous
                <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>Page {page} of {totalPages}<span class="hljs-tag">&lt;/<span class="hljs-name">span</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> setPage((prev) =&gt; Math.min(prev + 1, totalPages))}
                    disabled={page &gt;= totalPages}
                    style={{ padding: "6px 12px", marginLeft: "10px" }}
                &gt;
                    Next
                <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>
    );
}
</code></pre>
<p>To see this in action and try it for yourself, check out the live demo below:</p>
<div class="embed-wrapper">
        <iframe width="100%" height="350" src="https://codepen.io/Spruce_khalifa/embed/xbKerxQ" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="CodePen embed" scrolling="no" allowtransparency="true" allowfullscreen="true" loading="lazy"></iframe></div>
<p> </p>
<h2 id="heading-how-to-handle-typos-in-search">How to Handle Typos in Search</h2>
<p>Search is one of the oldest features on the web, but that doesn’t mean users always get it right. In fact, typos are incredibly common. Imagine a user searching for "PlayStation," but they accidentally type "PlauStation" instead. They still expect to see relevant results, and our search system should be forgiving enough to handle these small mistakes.</p>
<p>To achieve this, we are going to use a fuzzy search technique that matches similar words even if they’re not spelled exactly the same. We’ll implement this using an <strong>n-gram similarity algorithm</strong>, which breaks words into smaller segments (n-grams) and compares them to find matches.</p>
<h3 id="heading-step-1-building-the-n-gram-similarity-algorithm">Step 1: Building the n-gram Similarity Algorithm</h3>
<p>The n-gram similarity algorithm works by splitting both the search query and dataset values into small overlapping character sequences (n-grams) and comparing them:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// utils/nGramFuzzySearch.js</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> nGramFuzzySearch = <span class="hljs-function">(<span class="hljs-params">value, query</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> n = <span class="hljs-number">2</span>; <span class="hljs-comment">// Default to bigrams (two-character sequences)</span>

    <span class="hljs-keyword">const</span> valueGrams = generateNGrams(value.toLowerCase(), n);
    <span class="hljs-keyword">const</span> queryGrams = generateNGrams(query.toLowerCase(), n);

    <span class="hljs-keyword">const</span> intersection = valueGrams.filter(<span class="hljs-function">(<span class="hljs-params">gram</span>) =&gt;</span> queryGrams.includes(gram));

    <span class="hljs-keyword">return</span> intersection.length / <span class="hljs-built_in">Math</span>.max(valueGrams.length, queryGrams.length);
};

<span class="hljs-keyword">const</span> generateNGrams = <span class="hljs-function">(<span class="hljs-params">str, n</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> grams = [];

    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt;= str.length - n; i++) {
        grams.push(str.slice(i, i + n));
    }

    <span class="hljs-keyword">return</span> grams;
};
</code></pre>
<p>Here is how this will work if you try searching for query PlauStation and the product name is PlayStation:</p>
<p>First, the algorithm will generate bigrams (two-letter sequences) for both words:</p>
<p><code>PlayStation</code> → <code>["pl", "la", "ay", "ys", "st", "ta", "at", "ti", "io", "on"]</code><br><code>PlauStation</code> → <code>["pl", "la", "au", "us", "st", "ta", "at", "ti", "io", "on"]</code></p>
<p>Then, it calculates the similarity based on the number of overlapping bigrams. The higher the overlap, the closer the match. Since most bigrams match, the algorithm calculates a high similarity score, allowing it to recognize "PlauStation" as a likely match for "PlayStation", even with minor typos.</p>
<h3 id="heading-step-2-adding-fuzzy-search-into-the-search-filter">Step 2: Adding Fuzzy Search into the Search Filter</h3>
<p>Now, update your search filter to support a new <code>matchType</code> for fuzzy search:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Update in utils/search.js</span>

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

<span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">search</span>(<span class="hljs-params">options</span>) </span>{
    <span class="hljs-keyword">const</span> { fields, matchType } = options;

    <span class="hljs-keyword">return</span> <span class="hljs-function">(<span class="hljs-params">data, query</span>) =&gt;</span> {
        <span class="hljs-keyword">const</span> trimmedQuery = <span class="hljs-built_in">String</span>(query).trim().toLowerCase();

        <span class="hljs-keyword">if</span> (trimmedQuery === <span class="hljs-string">""</span>) {
            <span class="hljs-keyword">return</span> data;
        }

        <span class="hljs-keyword">return</span> data.filter(<span class="hljs-function">(<span class="hljs-params">item</span>) =&gt;</span> {
            <span class="hljs-keyword">const</span> fieldsArray = fields
                ? <span class="hljs-built_in">Array</span>.isArray(fields)
                    ? fields
                    : [fields]
                : getAllKeys(item);

            <span class="hljs-keyword">return</span> fieldsArray.some(<span class="hljs-function">(<span class="hljs-params">field</span>) =&gt;</span> {
                <span class="hljs-keyword">const</span> fieldValue = getFieldValue(item, field);
                <span class="hljs-keyword">if</span> (fieldValue == <span class="hljs-literal">null</span>) {
                    <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
                }

                <span class="hljs-keyword">const</span> stringValue = convertToString(fieldValue).toLowerCase();

                <span class="hljs-keyword">switch</span> (matchType) {
                    <span class="hljs-keyword">case</span> <span class="hljs-string">"exact"</span>:
                        <span class="hljs-keyword">return</span> stringValue === trimmedQuery;
                    <span class="hljs-keyword">case</span> <span class="hljs-string">"startsWith"</span>:
                        <span class="hljs-keyword">return</span> stringValue.startsWith(trimmedQuery);
                    <span class="hljs-keyword">case</span> <span class="hljs-string">"endsWith"</span>:
                        <span class="hljs-keyword">return</span> stringValue.endsWith(trimmedQuery);
                    <span class="hljs-keyword">case</span> <span class="hljs-string">"contains"</span>:
                        <span class="hljs-keyword">return</span> stringValue.includes(trimmedQuery);
                    <span class="hljs-keyword">case</span> <span class="hljs-string">"fuzzySearch"</span>: {
                        <span class="hljs-keyword">const</span> threshold = <span class="hljs-number">0.5</span>; <span class="hljs-comment">// Minimum similarity score required</span>
                        <span class="hljs-keyword">const</span> score = nGramFuzzySearch(stringValue, trimmedQuery);
                        <span class="hljs-keyword">return</span> score &gt;= threshold;
                    }
                    <span class="hljs-attr">default</span>:
                        <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">`Unsupported match type: <span class="hljs-subst">${matchType}</span>`</span>);
                }
            });
        });
    };
}
</code></pre>
<h3 id="heading-step-3-using-fuzzy-search-in-the-usesearch-hook">Step 3: Using Fuzzy Search in the <code>useSearch</code> Hook</h3>
<p>Now you can enable fuzzy search simply by passing <code>fuzzySearch</code> as the <code>matchType</code>:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> results = useSearch(
    data,
    query,
    search({
        <span class="hljs-attr">fields</span>: [<span class="hljs-string">"name"</span>],
        <span class="hljs-attr">matchType</span>: <span class="hljs-string">"fuzzySearch"</span>,
    })
);
</code></pre>
<p>Try it out on this <a target="_blank" href="https://codepen.io/Spruce_khalifa/pen/bNbZQNW?editors=0011">Live Demo</a> to see how even with a typo like <code>"PlauStation"</code>, your app still finds <code>"PlayStation"</code>.</p>
<div class="embed-wrapper">
        <iframe width="100%" height="350" src="https://codepen.io/Spruce_khalifa/embed/bNbZQNW" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="CodePen embed" scrolling="no" allowtransparency="true" allowfullscreen="true" loading="lazy"></iframe></div>
<p> </p>
<h2 id="heading-how-to-use-the-ready-made-usesearch-hook">How to Use the Ready-Made <code>useSearch</code> Hook</h2>
<p>If you’d rather not build everything from scratch, I've got you covered. I’ve published a fully typed, optimized version of the <code>useSearch</code> hook on npm, called <a target="_blank" href="https://www.npmjs.com/package/use-search-react#paginate"><strong>use-search-react</strong></a>. This package not only handles search but also comes with built-in support for sorting, pagination, grouping, and multiple fuzzy search algorithms so you can focus on building your app instead of reinventing the wheel.</p>
<h3 id="heading-how-to-use-it-in-your-component">How to Use it in Your Component</h3>
<h4 id="heading-step-1-install-the-hook">Step 1: Install the hook</h4>
<p>Simply install the package using npm:</p>
<pre><code class="lang-bash">npm install use-search-react
</code></pre>
<h4 id="heading-step-2-import-and-use-the-hook">Step 2: Import and use the hook</h4>
<p>Using the hook in your component is straightforward. For example, consider the following component that uses the hook to perform a fuzzy search on an array of data:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { useSearch, search } <span class="hljs-keyword">from</span> <span class="hljs-string">"use-search-react"</span>;
<span class="hljs-keyword">import</span> { useState } <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">SearchComponent</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">const</span> [query, setQuery] = useState(<span class="hljs-string">""</span>);

    <span class="hljs-keyword">const</span> data = [
        { <span class="hljs-attr">name</span>: <span class="hljs-string">"JavaScript"</span> },
        { <span class="hljs-attr">name</span>: <span class="hljs-string">"Python"</span> },
        { <span class="hljs-attr">name</span>: <span class="hljs-string">"Java"</span> }
    ];

    <span class="hljs-comment">// The 'search' function here is configured to perform a fuzzy search.</span>
    <span class="hljs-keyword">const</span> results = useSearch(
        data,
        query,
        search({
            <span class="hljs-attr">fields</span>: [<span class="hljs-string">"name"</span>],
            <span class="hljs-attr">matchType</span>: <span class="hljs-string">"fuzzy"</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">input</span>
                <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span>
                <span class="hljs-attr">value</span>=<span class="hljs-string">{query}</span>
                <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setQuery(e.target.value)}
                placeholder="Search..."
            /&gt;
            <span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
                {results.map((item, 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>&gt;</span>{item.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 class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
    );
}
</code></pre>
<p>This example shows how easy it is to use the hook in your React component. The package is built to handle even very large datasets—tens of thousands of records—while keeping your application responsive and efficient.</p>
<p>Here is an example of it working with ten thousand records of data</p>
<div class="embed-wrapper">
        <iframe width="100%" height="350" src="https://codepen.io/Spruce_khalifa/embed/xbKeZYg" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="CodePen embed" scrolling="no" allowtransparency="true" allowfullscreen="true" loading="lazy"></iframe></div>
<p> </p>
<p>For more detailed usage and additional configuration options (like pagination, sorting, or grouping), check out the full documentation on npm: <a target="_blank" href="https://www.npmjs.com/package/use-search-react">use-search-react Docs</a>.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Building a search system in React is more than just filtering data. It's about crafting an experience that feels intuitive and responsive for your users.</p>
<p>In this article, you learned how to build a custom <code>useSearch</code> hook that can address common challenges like performance issues, handling nested data, and even forgiving user typos with fuzzy search. We also looked at how to use pagination to manage large datasets.</p>
<p>Whether you decide to build your own from scratch or use the fully typed, ready-made version available on npm, you now have the search functionality that you can easily drop in any of your React projects.</p>
<p>Take these ideas, experiment with them, and adjust the implementation to fit your specific needs.</p>
<p>If you have any questions, feel free to find me on Twitter at <a target="_blank" href="https://x.com/sprucekhalifa">@sprucekhalifa</a>, and don’t forget to follow me for more tips and updates. Happy coding!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build a Countdown Timer with React – A Step-by-Step Guide ]]>
                </title>
                <description>
                    <![CDATA[ In this tutorial, you will learn how to build a custom countdown timer to track events using React.js. A countdown timer is a simple way to measure the time until an event happens. It counts down that time in reverse – like 5, 4, 3, 2, 1. It helps yo... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/build-a-countdown-timer-with-react-step-by-step/</link>
                <guid isPermaLink="false">670d1eef6f6de348bb7f216b</guid>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Tutorial ]]>
                    </category>
                
                    <category>
                        <![CDATA[ ReactHooks ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Franklin Ohaegbulam ]]>
                </dc:creator>
                <pubDate>Mon, 14 Oct 2024 13:38:55 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1724788718279/35a8ba3c-db35-49b6-ae41-14bcda547795.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In this tutorial, you will learn how to build a custom countdown timer to track events using React.js.</p>
<p>A countdown timer is a simple way to measure the time until an event happens. It counts down that time in reverse – like 5, 4, 3, 2, 1. It helps you manage the time leading up to upcoming events, product launches, or offers, and allows you to inform users about that timeline.</p>
<h3 id="heading-table-of-contents">Table of Contents</h3>
<ul>
<li><p><a class="post-section-overview" href="#heading-1-set-up-your-react-app">1. Set Up Your React App</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-2-create-the-count-down-component">2. Create the Count Down Component</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-3-implement-time-state-management-and-functionality">3. Implement Time State Management and Functionality</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-4-create-a-countdown-form">4. Create a Countdown Form</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-5-handle-the-countdown-start-stop-and-reset-functionality">5. Handle the Countdown Start, Stop, and Reset Functionality</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-6-format-the-event-date-and-time">6. Format the Event Date and Time</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-7-display-the-countdown-timer">7. Display the CountDown Timer</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-8-styling-the-countdown-timer-component">8. Styling the Countdown Timer Component</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h3 id="heading-prerequisites">Prerequisites</h3>
<p>You should have decent knowledge of HTML, CSS, and JavaScript to get the most out of this article.</p>
<p>Let's get started.</p>
<h2 id="heading-1-set-up-your-react-app">1. Set Up Your React App</h2>
<p>First, you’ll need to <a target="_blank" href="https://www.freecodecamp.org/news/how-to-build-a-react-app-different-ways/#heading-what-is-vite">create a React application</a> if you don’t already have one ready to use. In this tutorial, I’m using Vite. Then change into the new project directory by running the following commands in your code editor:</p>
<pre><code class="lang-bash">npm create vite countdown-timer

<span class="hljs-built_in">cd</span> countdown-timer
</code></pre>
<p>Run this command to start the app on the local server:</p>
<pre><code class="lang-bash">npm run dev
</code></pre>
<p>Now, you should see the project in your browser on <code>https://localhost/3000</code>.</p>
<h2 id="heading-2-create-the-count-down-component">2. Create the Count Down Component</h2>
<p>In the <code>src</code> folder of your React app, create a <code>components</code> directory, and inside it, create a <code>CountDown.jsx</code> file.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">/* components/CountDown.jsx */</span>

<span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

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

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"countdown-timer-container"</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> CountdownTimer;
</code></pre>
<h2 id="heading-3-implement-time-state-management-and-functionality">3. Implement Time State Management and Functionality</h2>
<p>Define the state variables using the useState hook. Update the <code>CountDown.jsx</code> file with the following code:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">/* components/CountDown.jsx */</span>

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

<span class="hljs-keyword">const</span> CountdownTimer = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> [eventName, setEventName] = useState(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> [eventDate, setEventDate] = useState(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> [countdownStarted, setCountdownStarted] = useState(<span class="hljs-literal">false</span>);
  <span class="hljs-keyword">const</span> [timeRemaining, setTimeRemaining] = 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> <span class="hljs-attr">className</span>=<span class="hljs-string">"countdown-timer-container"</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> CountdownTimer;
</code></pre>
<p>Here's a brief breakdown of the <code>useState</code>:</p>
<ul>
<li><p><code>eventName</code>: stores the name of the event for the countdown timer.</p>
</li>
<li><p><code>eventDate</code>: stores the date of the event for the countdown timer.</p>
</li>
<li><p><code>countdownStarted</code>: tracks whether the countdown timer has started.</p>
</li>
<li><p><code>timeRemaining</code>: stores the remaining time in milliseconds for the countdown.</p>
</li>
</ul>
<p>Now, we’ll implement the functionality of the countdown timer using the useEffect hook:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">/* components/CountDown.jsx */</span>

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

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

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

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">if</span> (countdownStarted &amp;&amp; eventDate) {
      <span class="hljs-keyword">const</span> countdownInterval = <span class="hljs-built_in">setInterval</span>(<span class="hljs-function">() =&gt;</span> {
        <span class="hljs-keyword">const</span> currentTime = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().getTime();
        <span class="hljs-keyword">const</span> eventTime = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(eventDate).getTime();
        <span class="hljs-keyword">let</span> remainingTime = eventTime - currentTime;

        <span class="hljs-keyword">if</span> (remainingTime &lt;= <span class="hljs-number">0</span>) {
          remainingTime = <span class="hljs-number">0</span>;
          <span class="hljs-built_in">clearInterval</span>(countdownInterval);
          alert(<span class="hljs-string">"Countdown complete!"</span>);
        }

        setTimeRemaining(remainingTime);
      }, <span class="hljs-number">1000</span>);

      <span class="hljs-keyword">return</span> <span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">clearInterval</span>(countdownInterval);
    }
  }, [countdownStarted, eventDate, timeRemaining]);

 <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">"countdown-timer-container"</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> CountdownTimer;
</code></pre>
<p>The <code>useEffect</code> hook runs whenever <code>countdownStarted</code> or <code>eventDate</code> changes. It sets up an interval that updates <code>timeRemaining</code> every second based on the current time and event time. If the remaining time becomes less than or equal to 0, it stops the interval and triggers the notification "Countdown complete!"</p>
<pre><code class="lang-javascript"><span class="hljs-comment">/* components/CountDown.jsx */</span>

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

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

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

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">if</span> (countdownStarted) {
      <span class="hljs-built_in">document</span>.title = eventName;
    }
  }, [countdownStarted, eventName]);

 <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">"countdown-timer-container"</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> CountdownTimer;
</code></pre>
<p>Here, the <code>useEffect</code> hook runs whenever <code>countdownStarted</code> or <code>eventName</code> changes. It updates the countdown timer title to display the <code>eventName</code> when the countdown timer is started.</p>
<h2 id="heading-4-create-a-countdown-form">4. Create a Countdown Form</h2>
<p>To have control over the countdown timer, you’ll need to create a form with two inputs for the name and date of the event. Then, add the following code:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">/* components/CountDown.jsx */</span>

<span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

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

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

 <span class="hljs-keyword">return</span> (
 <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"countdown-timer-container"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"countdown-name"</span>&gt;</span>
        {countdownStarted ? eventName : "Countdown Timer"}
      <span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>

      {!countdownStarted ? (
        <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"countdown-form"</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>Event Name<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
            <span class="hljs-attr">name</span>=<span class="hljs-string">"title"</span>
            <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span>
            <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Enter event name"</span>
            <span class="hljs-attr">value</span>=<span class="hljs-string">{eventName}</span>
            <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setEventName(e.target.value)}
          /&gt;

          <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"date-picker"</span>&gt;</span>Event Date<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
            <span class="hljs-attr">name</span>=<span class="hljs-string">"date-picker"</span>
            <span class="hljs-attr">type</span>=<span class="hljs-string">"date"</span>
            <span class="hljs-attr">value</span>=<span class="hljs-string">{eventDate}</span>
            <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setEventDate(e.target.value)}
            onClick={(e) =&gt; (e.target.type = "date")}
          /&gt;
          <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handleSetCountdown}</span>&gt;</span>Start Countdown<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>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> CountdownTimer;
</code></pre>
<p>Here's a brief breakdown of the <code>useState</code>:</p>
<ul>
<li><p><code>eventName</code>: stores the name of the event for the countdown timer.</p>
</li>
<li><p><code>countdown-name</code>: displays the "Countdown Timer" by default or updates to the  <code>eventName</code> entered once the countdown has started.</p>
</li>
</ul>
<p>The form includes:</p>
<ul>
<li><p>The input field with the name <code>title</code> and label <code>Event Name</code> update the <code>eventName</code> state value.</p>
</li>
<li><p>The input field with the name <code>date-picker</code> allow users to select a date and control the  <code>eventDate</code> state value.</p>
</li>
<li><p>The button <code>Start Countdown</code> triggers the <code>handleSetCountdown</code> function when clicked to initiate the countdown.</p>
</li>
</ul>
<h2 id="heading-5-handle-the-countdown-start-stop-and-reset-functionality">5. Handle the Countdown Start, Stop, and Reset Functionality</h2>
<p>Next, update the <code>handleSetCountdown</code> function to store the event name and date in the local storage using <code>localStorage.setItem</code>. localStorage is a web API that enables users to store data as key-value pairs persistently, even when the browser is closed or refreshed.</p>
<p>The code is as follows:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">/* components/CountDown.jsx */</span>

<span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

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

    <span class="hljs-keyword">const</span> handleSetCountdown = <span class="hljs-function">() =&gt;</span> {
    setCountdownStarted(<span class="hljs-literal">true</span>);
    <span class="hljs-built_in">localStorage</span>.setItem(<span class="hljs-string">"eventDate"</span>, eventDate);
    <span class="hljs-built_in">localStorage</span>.setItem(<span class="hljs-string">"eventName"</span>, eventName);
  };

 <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">"countdown-timer-container"</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> CountdownTimer;
</code></pre>
<p>Now, create the <code>handleStopCountdown</code> and <code>handleResetCountdown</code> functions to stop the countdown timer by updating the <code>countdownStarted</code> state to <code>false</code>.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">/* components/CountDown.jsx */</span>

<span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

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

  <span class="hljs-keyword">const</span> handleStopCountdown = <span class="hljs-function">() =&gt;</span> {
    setCountdownStarted(<span class="hljs-literal">false</span>);
    setTimeRemaining(<span class="hljs-number">0</span>);
  };

  <span class="hljs-keyword">const</span> handleResetCountdown = <span class="hljs-function">() =&gt;</span> {
    setCountdownStarted(<span class="hljs-literal">false</span>);
    setEventDate(<span class="hljs-string">""</span>);
    setEventName(<span class="hljs-string">""</span>);
    setTimeRemaining(<span class="hljs-number">0</span>);
    <span class="hljs-built_in">localStorage</span>.removeItem(<span class="hljs-string">"eventDate"</span>);
    <span class="hljs-built_in">localStorage</span>.removeItem(<span class="hljs-string">"eventName"</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">"countdown-timer-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">"control-buttons"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handleStopCountdown}</span>&gt;</span>Stop<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">{handleResetCountdown}</span>&gt;</span>Reset<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>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> CountdownTimer;
</code></pre>
<p>Here:</p>
<ul>
<li><p><code>handleStopCountdown</code>: resets the <code>timeRemaining</code> state to zero.</p>
</li>
<li><p><code>handleResetCountdown</code>: resets the countdown timer to its initial state. It clears the remaining time states and removes the event date and event name from local storage using <code>localStorage.removeItem()</code>.</p>
</li>
</ul>
<h2 id="heading-6-format-the-event-date-and-time">6. Format the Event Date and Time</h2>
<p>Let's convert date and time data into a readable format.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">/* components/CountDown.jsx */</span>

<span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

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

  <span class="hljs-keyword">const</span> formatDate = <span class="hljs-function">(<span class="hljs-params">date</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> options = { <span class="hljs-attr">month</span>: <span class="hljs-string">"long"</span>, <span class="hljs-attr">day</span>: <span class="hljs-string">"numeric"</span>, <span class="hljs-attr">year</span>: <span class="hljs-string">"numeric"</span> };
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(date).toLocaleDateString(<span class="hljs-string">"en-US"</span>, options);
  };

  <span class="hljs-keyword">const</span> formatTime = <span class="hljs-function">(<span class="hljs-params">time</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> seconds = <span class="hljs-built_in">Math</span>.floor((time / <span class="hljs-number">1000</span>) % <span class="hljs-number">60</span>);
    <span class="hljs-keyword">const</span> minutes = <span class="hljs-built_in">Math</span>.floor((time / (<span class="hljs-number">1000</span> * <span class="hljs-number">60</span>)) % <span class="hljs-number">60</span>);
    <span class="hljs-keyword">const</span> hours = <span class="hljs-built_in">Math</span>.floor((time / (<span class="hljs-number">1000</span> * <span class="hljs-number">60</span> * <span class="hljs-number">60</span>)) % <span class="hljs-number">24</span>);
    <span class="hljs-keyword">const</span> days = <span class="hljs-built_in">Math</span>.floor(time / (<span class="hljs-number">1000</span> * <span class="hljs-number">60</span> * <span class="hljs-number">60</span> * <span class="hljs-number">24</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">"countdown-display"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"countdown-value"</span>&gt;</span>
          {days.toString().padStart(2, "0")} <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>days<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">"countdown-value"</span>&gt;</span>
          {hours.toString().padStart(2, "0")} <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span> hours<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">"countdown-value"</span>&gt;</span>
          {minutes.toString().padStart(2, "0")} <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>minutes<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">"countdown-value"</span>&gt;</span>
          {seconds.toString().padStart(2, "0")} <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>seconds<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>
    );
  };

 <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">"countdown-timer-container"</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> CountdownTimer;
</code></pre>
<p>Here's a brief breakdown of the functions:</p>
<ul>
<li><p><code>formatDate</code>: formats the date input into a human-readable date string.</p>
</li>
<li><p><code>formatTime</code>: takes a time in milliseconds as input and calculates the days, hours, minutes, and seconds of the timer. The <code>.toString().padStart(2, "0")</code> returns the formatted time as two characters by appending 0 at the beginning of the time only if the length of the number is less than 2.</p>
</li>
</ul>
<p>Here are the complete contents of the <code>CountDown.jsx</code> file:</p>
<pre><code class="lang-javascript"> <span class="hljs-comment">/* components/CountDown.jsx */</span>

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

<span class="hljs-keyword">const</span> CountdownTimer = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> [eventName, setEventName] = useState(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> [eventDate, setEventDate] = useState(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> [countdownStarted, setCountdownStarted] = useState(<span class="hljs-literal">false</span>);
  <span class="hljs-keyword">const</span> [timeRemaining, setTimeRemaining] = useState(<span class="hljs-number">0</span>);

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">if</span> (countdownStarted &amp;&amp; eventDate) {
      <span class="hljs-keyword">const</span> countdownInterval = <span class="hljs-built_in">setInterval</span>(<span class="hljs-function">() =&gt;</span> {
        <span class="hljs-keyword">const</span> currentTime = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().getTime();
        <span class="hljs-keyword">const</span> eventTime = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(eventDate).getTime();
        <span class="hljs-keyword">let</span> remainingTime = eventTime - currentTime;

        <span class="hljs-keyword">if</span> (remainingTime &lt;= <span class="hljs-number">0</span>) {
          remainingTime = <span class="hljs-number">0</span>;
          <span class="hljs-built_in">clearInterval</span>(countdownInterval);
          alert(<span class="hljs-string">"Countdown complete!"</span>);
        }

        setTimeRemaining(remainingTime);
      }, <span class="hljs-number">1000</span>);

      <span class="hljs-keyword">return</span> <span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">clearInterval</span>(countdownInterval);
    }
  }, [countdownStarted, eventDate, timeRemaining]);

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">if</span> (countdownStarted) {
      <span class="hljs-built_in">document</span>.title = eventName;
    }
  }, [countdownStarted, eventName]);

  <span class="hljs-keyword">const</span> handleSetCountdown = <span class="hljs-function">() =&gt;</span> {
    setCountdownStarted(<span class="hljs-literal">true</span>);
    <span class="hljs-built_in">localStorage</span>.setItem(<span class="hljs-string">"eventDate"</span>, eventDate);
    <span class="hljs-built_in">localStorage</span>.setItem(<span class="hljs-string">"eventName"</span>, eventName);
  };

  <span class="hljs-keyword">const</span> handleStopCountdown = <span class="hljs-function">() =&gt;</span> {
    setCountdownStarted(<span class="hljs-literal">false</span>);
    setTimeRemaining(<span class="hljs-number">0</span>);
  };

  <span class="hljs-keyword">const</span> handleResetCountdown = <span class="hljs-function">() =&gt;</span> {
    setCountdownStarted(<span class="hljs-literal">false</span>);
    setEventDate(<span class="hljs-string">""</span>);
    setEventName(<span class="hljs-string">""</span>);
    setTimeRemaining(<span class="hljs-number">0</span>);
    <span class="hljs-built_in">localStorage</span>.removeItem(<span class="hljs-string">"eventDate"</span>);
    <span class="hljs-built_in">localStorage</span>.removeItem(<span class="hljs-string">"eventName"</span>);
  };

  <span class="hljs-keyword">const</span> formatDate = <span class="hljs-function">(<span class="hljs-params">date</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> options = { <span class="hljs-attr">month</span>: <span class="hljs-string">"long"</span>, <span class="hljs-attr">day</span>: <span class="hljs-string">"numeric"</span>, <span class="hljs-attr">year</span>: <span class="hljs-string">"numeric"</span> };
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(date).toLocaleDateString(<span class="hljs-string">"en-US"</span>, options);
  };

  <span class="hljs-keyword">const</span> formatTime = <span class="hljs-function">(<span class="hljs-params">time</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> seconds = <span class="hljs-built_in">Math</span>.floor((time / <span class="hljs-number">1000</span>) % <span class="hljs-number">60</span>);
    <span class="hljs-keyword">const</span> minutes = <span class="hljs-built_in">Math</span>.floor((time / (<span class="hljs-number">1000</span> * <span class="hljs-number">60</span>)) % <span class="hljs-number">60</span>);
    <span class="hljs-keyword">const</span> hours = <span class="hljs-built_in">Math</span>.floor((time / (<span class="hljs-number">1000</span> * <span class="hljs-number">60</span> * <span class="hljs-number">60</span>)) % <span class="hljs-number">24</span>);
    <span class="hljs-keyword">const</span> days = <span class="hljs-built_in">Math</span>.floor(time / (<span class="hljs-number">1000</span> * <span class="hljs-number">60</span> * <span class="hljs-number">60</span> * <span class="hljs-number">24</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">"countdown-display"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"countdown-value"</span>&gt;</span>
          {days.toString().padStart(2, "0")} <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>days<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">"countdown-value"</span>&gt;</span>
          {hours.toString().padStart(2, "0")} <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span> hours<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">"countdown-value"</span>&gt;</span>
          {minutes.toString().padStart(2, "0")} <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>minutes<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">"countdown-value"</span>&gt;</span>
          {seconds.toString().padStart(2, "0")} <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>seconds<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>
    );
  };

  <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">"countdown-timer-container"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"countdown-name"</span>&gt;</span>
        {countdownStarted ? eventName : "Countdown Timer"}
      <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">"countdown-date"</span>&gt;</span>
        {countdownStarted &amp;&amp; formatDate(eventDate)}
      <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>

      {!countdownStarted ? (
        <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"countdown-form"</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>Event Name<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
            <span class="hljs-attr">name</span>=<span class="hljs-string">"title"</span>
            <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span>
            <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Enter event name"</span>
            <span class="hljs-attr">value</span>=<span class="hljs-string">{eventName}</span>
            <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setEventName(e.target.value)}
          /&gt;

          <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"date-picker"</span>&gt;</span>Event Date<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
            <span class="hljs-attr">name</span>=<span class="hljs-string">"date-picker"</span>
            <span class="hljs-attr">type</span>=<span class="hljs-string">"date"</span>
            <span class="hljs-attr">value</span>=<span class="hljs-string">{eventDate}</span>
            <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setEventDate(e.target.value)}
            onClick={(e) =&gt; (e.target.type = "date")}
          /&gt;
          <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handleSetCountdown}</span>&gt;</span>Start Countdown<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;&gt;</span>
          {formatTime(timeRemaining)}
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"control-buttons"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handleStopCountdown}</span>&gt;</span>Stop<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">{handleResetCountdown}</span>&gt;</span>Reset<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/&gt;</span></span>
      )}
    &lt;/div&gt;
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> CountdownTimer;
</code></pre>
<h2 id="heading-7-display-the-countdown-timer">7. Display the CountDown Timer</h2>
<p>Import <code>CountDownTimer</code> in the <code>App.jsx</code>, replacing the default code with this:</p>
<pre><code class="lang-javascript"> <span class="hljs-comment">/* App.jsx */</span>

<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> CountdownTimer <span class="hljs-keyword">from</span> <span class="hljs-string">"./components/CountDown"</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">"App"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">CountdownTimer</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>And that's it! Your countdown timer app should be rendered on  <code>localhost:3000</code> in the browser.</p>
<h2 id="heading-8-styling-the-countdown-timer-component">8. Styling the Countdown Timer Component</h2>
<p>Lastly, update the <code>index.css</code> file in the same directory of your project by adding the following styles:</p>
<pre><code class="lang-css"><span class="hljs-keyword">@import</span> url(<span class="hljs-string">"https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&amp;family=Open+Sans:wght@400;500;700&amp;display=swap"</span>);

* {
  <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">body</span> {
  <span class="hljs-attribute">background</span>: <span class="hljs-built_in">url</span>(<span class="hljs-string">"./img/bg-img.jpg"</span>) top center;
  <span class="hljs-attribute">background-size</span>: cover;
  <span class="hljs-attribute">background-repeat</span>: no-repeat;
  <span class="hljs-attribute">background-attachment</span>: fixed;
  <span class="hljs-attribute">font-family</span>: <span class="hljs-string">"Inter"</span>, sans-serif;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">1rem</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">justify-content</span>: center;
  <span class="hljs-attribute">align-items</span>: center;
  <span class="hljs-attribute">flex-direction</span>: column;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">1rem</span>;
}

<span class="hljs-selector-class">.countdown-form</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#f6f6f6</span>;
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">flex-direction</span>: column;
  <span class="hljs-attribute">justify-content</span>: center;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">1.5rem</span>;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
  <span class="hljs-attribute">max-width</span>: <span class="hljs-number">400px</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">12px</span>;
  <span class="hljs-attribute">box-shadow</span>: <span class="hljs-number">0</span> <span class="hljs-number">4px</span> <span class="hljs-number">6px</span> <span class="hljs-built_in">rgba</span>(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0.1</span>);
}

<span class="hljs-selector-tag">label</span> {
  <span class="hljs-attribute">font-weight</span>: <span class="hljs-number">600</span>;
  <span class="hljs-attribute">margin-bottom</span>: <span class="hljs-number">0.5rem</span>;
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#333</span>;
}

<span class="hljs-selector-tag">input</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#d1f1ee</span>;
  <span class="hljs-attribute">border</span>: <span class="hljs-number">1px</span> solid <span class="hljs-number">#dfdfdf</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">6px</span>;
  <span class="hljs-attribute">outline</span>: none;
  <span class="hljs-attribute">margin-bottom</span>: <span class="hljs-number">1rem</span>;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">0.75rem</span>;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">1rem</span>;
  <span class="hljs-attribute">transition</span>: border-color <span class="hljs-number">0.2s</span> ease;
}

<span class="hljs-selector-tag">input</span><span class="hljs-selector-pseudo">:focus</span> {
  <span class="hljs-attribute">border-color</span>: <span class="hljs-number">#038a7f</span>;
}

<span class="hljs-selector-tag">button</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#038a7f</span>;
  <span class="hljs-attribute">border</span>: none;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">6px</span>;
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#fff</span>;
  <span class="hljs-attribute">cursor</span>: pointer;
  <span class="hljs-attribute">outline</span>: none;
  <span class="hljs-attribute">margin-top</span>: <span class="hljs-number">1rem</span>;
  <span class="hljs-attribute">text-transform</span>: uppercase;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">2.75rem</span>;
  <span class="hljs-attribute">font-weight</span>: <span class="hljs-number">600</span>;
  <span class="hljs-attribute">letter-spacing</span>: <span class="hljs-number">0.5px</span>;
  <span class="hljs-attribute">transition</span>: background-color <span class="hljs-number">0.2s</span> ease;
}

<span class="hljs-selector-tag">button</span><span class="hljs-selector-pseudo">:hover</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#005a53</span>;
}

<span class="hljs-selector-class">.countdown-message</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">font-size</span>: <span class="hljs-built_in">clamp</span>(<span class="hljs-number">1.25rem</span>, <span class="hljs-number">4vw</span>, <span class="hljs-number">1.5rem</span>);
  <span class="hljs-attribute">margin</span>: <span class="hljs-number">1rem</span> <span class="hljs-number">0</span>;
}

<span class="hljs-selector-class">.countdown-name</span> {
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#fff</span>;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-built_in">clamp</span>(<span class="hljs-number">1.5rem</span>, <span class="hljs-number">5vw</span>, <span class="hljs-number">2rem</span>);
  <span class="hljs-attribute">margin-bottom</span>: <span class="hljs-number">1rem</span>;
  <span class="hljs-attribute">text-align</span>: center;
  <span class="hljs-attribute">text-shadow</span>: <span class="hljs-number">2px</span> <span class="hljs-number">2px</span> <span class="hljs-number">4px</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.3</span>);
}

<span class="hljs-selector-class">.countdown-date</span> {
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#eafbfa</span>;
  <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span> <span class="hljs-number">0</span> <span class="hljs-number">1.5rem</span>;
  <span class="hljs-attribute">text-align</span>: center;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-built_in">clamp</span>(<span class="hljs-number">1rem</span>, <span class="hljs-number">3vw</span>, <span class="hljs-number">1.25rem</span>);
  <span class="hljs-attribute">text-shadow</span>: <span class="hljs-number">2px</span> <span class="hljs-number">2px</span> <span class="hljs-number">4px</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.3</span>);
}

<span class="hljs-selector-class">.countdown-display</span> {
  <span class="hljs-attribute">display</span>: grid;
  <span class="hljs-attribute">grid-template-columns</span>: <span class="hljs-built_in">repeat</span>(auto-fit, minmax(<span class="hljs-number">80px</span>, <span class="hljs-number">1</span>fr));
  <span class="hljs-attribute">gap</span>: <span class="hljs-number">1rem</span>;
  <span class="hljs-attribute">justify-content</span>: center;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">0.5rem</span>;
  <span class="hljs-attribute">max-width</span>: <span class="hljs-number">600px</span>;
  <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span> auto;
}

<span class="hljs-selector-class">.countdown-value</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#2f5d6f</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">50%</span>;
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#03d5c0</span>;
  <span class="hljs-attribute">aspect-ratio</span>: <span class="hljs-number">1</span>;
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">flex-direction</span>: column;
  <span class="hljs-attribute">align-items</span>: center;
  <span class="hljs-attribute">justify-content</span>: center;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">1rem</span>;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-built_in">clamp</span>(<span class="hljs-number">1.5rem</span>, <span class="hljs-number">5vw</span>, <span class="hljs-number">2.5rem</span>);
  <span class="hljs-attribute">font-weight</span>: <span class="hljs-number">700</span>;
  <span class="hljs-attribute">box-shadow</span>: <span class="hljs-number">0</span> <span class="hljs-number">4px</span> <span class="hljs-number">6px</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">transition</span>: transform <span class="hljs-number">0.2s</span> ease;
}

<span class="hljs-selector-class">.countdown-value</span><span class="hljs-selector-pseudo">:hover</span> {
  <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">scale</span>(<span class="hljs-number">1.05</span>);
}

<span class="hljs-selector-class">.countdown-value</span> &gt; <span class="hljs-selector-tag">span</span> {
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#fff</span>;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-built_in">clamp</span>(<span class="hljs-number">0.75rem</span>, <span class="hljs-number">2vw</span>, <span class="hljs-number">0.875rem</span>);
  <span class="hljs-attribute">letter-spacing</span>: <span class="hljs-number">1px</span>;
  <span class="hljs-attribute">text-transform</span>: uppercase;
  <span class="hljs-attribute">margin-top</span>: <span class="hljs-number">0.2rem</span>;
  <span class="hljs-attribute">font-weight</span>: <span class="hljs-number">500</span>;
}

<span class="hljs-selector-class">.control-buttons</span> {
  <span class="hljs-attribute">margin-top</span>: <span class="hljs-number">2rem</span>;
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">justify-content</span>: center;
  <span class="hljs-attribute">gap</span>: <span class="hljs-number">1rem</span>;
  <span class="hljs-attribute">flex-wrap</span>: wrap;
}

<span class="hljs-selector-class">.control-buttons</span> &gt; <span class="hljs-selector-tag">button</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#03b4a2</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">50%</span>;
  <span class="hljs-attribute">width</span>: <span class="hljs-built_in">clamp</span>(<span class="hljs-number">45px</span>, <span class="hljs-number">8vw</span>, <span class="hljs-number">50px</span>);
  <span class="hljs-attribute">height</span>: <span class="hljs-built_in">clamp</span>(<span class="hljs-number">45px</span>, <span class="hljs-number">8vw</span>, <span class="hljs-number">50px</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">display</span>: flex;
  <span class="hljs-attribute">align-items</span>: center;
  <span class="hljs-attribute">justify-content</span>: center;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-built_in">clamp</span>(<span class="hljs-number">0.65rem</span>, <span class="hljs-number">2vw</span>, <span class="hljs-number">0.775rem</span>);
}

<span class="hljs-selector-class">.control-buttons</span> <span class="hljs-selector-tag">button</span><span class="hljs-selector-pseudo">:hover</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#0b7c71</span>;
  <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">scale</span>(<span class="hljs-number">1.1</span>);
}

<span class="hljs-keyword">@media</span> (<span class="hljs-attribute">max-width:</span> <span class="hljs-number">480px</span>) {
  <span class="hljs-selector-class">.countdown-display</span> {
    <span class="hljs-attribute">grid-template-columns</span>: <span class="hljs-built_in">repeat</span>(<span class="hljs-number">2</span>, <span class="hljs-number">1</span>fr);
    <span class="hljs-attribute">gap</span>: <span class="hljs-number">0.75rem</span>;
  }

  <span class="hljs-selector-class">.countdown-value</span> {
    <span class="hljs-attribute">font-size</span>: <span class="hljs-built_in">clamp</span>(<span class="hljs-number">1.25rem</span>, <span class="hljs-number">4vw</span>, <span class="hljs-number">1.75rem</span>);
  }

  <span class="hljs-selector-class">.countdown-value</span> &gt; <span class="hljs-selector-tag">span</span> {
    <span class="hljs-attribute">font-size</span>: <span class="hljs-number">0.75rem</span>;
  }

  <span class="hljs-selector-class">.control-buttons</span> {
    <span class="hljs-attribute">margin-top</span>: <span class="hljs-number">1.5rem</span>;
  }
}

<span class="hljs-keyword">@media</span> (<span class="hljs-attribute">max-width:</span> <span class="hljs-number">360px</span>) {
  <span class="hljs-selector-tag">body</span> {
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">0.75rem</span>;
  }

  <span class="hljs-selector-class">.countdown-form</span> {
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">1rem</span>;
  }

  <span class="hljs-selector-class">.countdown-name</span> {
    <span class="hljs-attribute">font-size</span>: <span class="hljs-number">1.25rem</span>;
  }

  <span class="hljs-selector-class">.countdown-date</span> {
    <span class="hljs-attribute">font-size</span>: <span class="hljs-number">1rem</span>;
  }

  <span class="hljs-selector-class">.control-buttons</span> &gt; <span class="hljs-selector-tag">button</span> {
    <span class="hljs-attribute">width</span>: <span class="hljs-number">40px</span>;
    <span class="hljs-attribute">height</span>: <span class="hljs-number">40px</span>;
  }
}
</code></pre>
<p>Congratulations, you’ve finished building your Countdown timer app!</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this article, you've learned how to build a basic React countdown timer app and how to work with the browser's local storage.</p>
<p>The code implemented in this article is accessible in this <a target="_blank" href="https://github.com/frankiefab100/countdown-timer">GitHub repository</a>. To learn more about web development and technology, check out my <a target="_blank" href="https://frankiefab.hashnode.dev/">blog</a> or connect with me on <a target="_blank" href="https://twitter.com/frankiefab100">X(Twitter)</a> and <a target="_blank" href="https://linkedin.com/in/frankiefab100/">LinkedIn</a>.</p>
<p>Thank you for reading.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Learn React Hooks – Common Hooks Explained with Code Examples ]]>
                </title>
                <description>
                    <![CDATA[ Web development is a popular field in the tech industry. It involves building web software using HTML, CSS, and JavaScript – sometimes with the help of various frameworks and libraries. Using libraries and frameworks allows developers to focus more o... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/learn-react-hooks-with-example-code/</link>
                <guid isPermaLink="false">66f43493173ff3821d17571a</guid>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ ReactHooks ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Prankur Pandey ]]>
                </dc:creator>
                <pubDate>Wed, 25 Sep 2024 16:04:35 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1727212733982/7c9b8ae3-e8ac-4e20-b154-7edc60a6985a.avif" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Web development is a popular field in the tech industry. It involves building web software using HTML, CSS, and JavaScript – sometimes with the help of various frameworks and libraries.</p>
<p>Using libraries and frameworks allows developers to focus more on the development while the tools take care of certain functionality in the background. And React.js is a popular JavaScript library for building front-end applications.</p>
<p>In this article, you’ll learn about the backbone of React which is <strong>Hooks,</strong> and how they can make your life easier as a developer.</p>
<h2 id="heading-what-well-cover">What We’ll Cover:</h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-prerequisites">Prerequisites:</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-getting-started">Getting Started</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-are-hooks">What are Hooks?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-types-of-react-hooks">Types of React Hooks</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-state-management-hooks">State Management Hooks</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-effect-hooks">Effect Hooks</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-ref-hook">Ref Hook</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-performance-hooks">Performance Hooks</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-context-hook">Context Hook</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-transition-hook">Transition Hook</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-some-random-hooks">Some Random Hooks</a></p>
</li>
</ul>
</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>You should know the basics of JavaScript.</p>
</li>
<li><p>You should also know the basics of React, like setting up an app, updating it, and using state.</p>
</li>
</ul>
<h2 id="heading-getting-started">Getting Started</h2>
<p>So you've decided to build a React app—congratulations! 🎉 But as you dive into the world of React hooks, you might find yourself feeling overwhelmed. With a plethora of hooks available, figuring out which ones to use and when can be a bit daunting.</p>
<p>Well, don’t worry – in this guide, I’ll break down every major hook so you can see how they fit together. We’ll also discuss which ones you'll use more frequently versus more rarely.</p>
<p>By the end of this article, you'll have a comprehensive map of React hooks and their practical applications.</p>
<h2 id="heading-what-are-hooks"><strong>What are Hooks?</strong></h2>
<p>In JavaScript, we use variables to store data and later perform operations on that data.</p>
<p>Hooks in React work similarly, but they are designed to manage state in <strong>functional components</strong>. Instead of manually declaring a single variable, hooks like <code>useState</code> give us a way to declare stateful values along with a setter function to update that state.</p>
<p>Here’s a simple example:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React, { useState } <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">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-comment">// Initialize state and state updater</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>
<p>In this code, I use the <code>useState</code> hook to declare a piece of state called <code>count</code> and set its initial value to 0. The <code>setCount</code> function allows us to update this state. Every time the button is clicked, we use <code>setCount</code> to increase <code>count</code> by 1. When the state updates, React re-renders the component to reflect the change.</p>
<p>Unlike declaring <code>let count = 0</code>, using <code>useState</code> lets React remember the state across renders and ensures that the UI updates correctly.</p>
<h2 id="heading-types-of-react-hooks">Types of React Hooks</h2>
<p>To make things easier, you can think of React hooks as falling into eight major categories:</p>
<ul>
<li><p><strong>State Management Hooks</strong> – For handling state.</p>
</li>
<li><p><strong>Effect Hooks</strong> – For side effects.</p>
</li>
<li><p><strong>Ref Hooks</strong> – For referencing JavaScript values or DOM elements.</p>
</li>
<li><p><strong>Performance Hooks</strong> – For optimizing performance.</p>
</li>
<li><p><strong>Context Hooks</strong> – For accessing React context.</p>
</li>
<li><p><strong>Transition Hooks</strong> – For smoother user experiences.</p>
</li>
<li><p><strong>Some Random Hooks</strong> – Special-purpose hooks.</p>
</li>
<li><p><strong>New Hooks (React 19)</strong> – Cutting-edge tools introduced in the latest React version.</p>
</li>
</ul>
<p>In React, you can also build custom hooks for different use cases. Every hook starts with the <code>use</code> keyword – even custom hooks start with this structure. This keyword is reserved for Hooks in React.</p>
<p>Let’s explore these hooks in detail.</p>
<h3 id="heading-state-management-hooks"><strong>State Management Hooks</strong></h3>
<h4 id="heading-1-usestate"><strong>1.</strong> <code>useState</code></h4>
<p>The <code>useState</code> hook is the bread and butter of React. It’s the most commonly used hook, and it’s key for managing state in functional components. With <code>useState</code>, you can capture user inputs, show or hide components, and manage numbers, like in an ecommerce app with a shopping cart.</p>
<p><code>useState</code> is versatile and straightforward: you initialize it with a value, and it returns a state variable and an updater function.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> React, { useState } <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">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-comment">// Initialize state and state updater</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>
<p><strong>Code explanation</strong>: <code>useState</code> initializes the state (count) and provides a function (<code>setCount</code>) to update that state.</p>
<h4 id="heading-2-usereducer"><strong>2.</strong> <code>useReducer</code></h4>
<p>When <code>useState</code> isn’t enough, <code>useReducer</code> comes into play. This hook is perfect for managing complex state logic.</p>
<p>It uses a reducer function to simplify state updates and is especially useful when multiple state variables are interdependent or when actions need to be dispatched.</p>
<p>Think of it as an upgrade for managing more complicated state scenarios. Here’s an example:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> React, { useReducer } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-keyword">const</span> initialState = { <span class="hljs-attr">count</span>: <span class="hljs-number">0</span> };

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">reducer</span>(<span class="hljs-params">state, action</span>) </span>{
  <span class="hljs-keyword">switch</span> (action.type) {
    <span class="hljs-keyword">case</span> <span class="hljs-string">'increment'</span>:
      <span class="hljs-keyword">return</span> { <span class="hljs-attr">count</span>: state.count + <span class="hljs-number">1</span> };
    <span class="hljs-keyword">case</span> <span class="hljs-string">'decrement'</span>:
      <span class="hljs-keyword">return</span> { <span class="hljs-attr">count</span>: state.count - <span class="hljs-number">1</span> };
    <span class="hljs-keyword">default</span>:
      <span class="hljs-keyword">return</span> state;
  }
}

<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> [state, dispatch] = useReducer(reducer, initialState);

  <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: {state.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">{()</span> =&gt;</span> dispatch({ type: 'increment' })}&gt;+<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> dispatch({ type: 'decrement' })}&gt;-<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><strong>Code explanation</strong>: <code>useReducer</code> is useful for managing complex state updates, like handling multiple related actions.</p>
<p><strong>3.</strong> <code>useSyncExternalStore</code><br><code>useSyncExternalStore</code> is a hook for integrating non-React state stores into your React components.</p>
<p>While not commonly used, it’s crucial if you’re building your own state management library from scratch.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> React, { useSyncExternalStore } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-keyword">const</span> externalStore = {
  <span class="hljs-attr">subscribe</span>: <span class="hljs-function">(<span class="hljs-params">callback</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> interval = <span class="hljs-built_in">setInterval</span>(callback, <span class="hljs-number">1000</span>);
    <span class="hljs-keyword">return</span> <span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">clearInterval</span>(interval);
  },
  <span class="hljs-attr">getSnapshot</span>: <span class="hljs-function">() =&gt;</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().toLocaleTimeString(),
};

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Clock</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> time = useSyncExternalStore(externalStore.subscribe, externalStore.getSnapshot);
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>{time}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>;
}
</code></pre>
<p><strong>Code explanation</strong>: <code>useSyncExternalStore</code> lets you connect your React component to non-React data sources, like global stores.</p>
<h3 id="heading-effect-hooks"><strong>Effect Hooks</strong></h3>
<p><strong>1.</strong> <code>useEffect</code><br>The <code>useEffect</code> hook performs side effects on your components. Whether you’re interacting with the DOM or fetching data, <code>useEffect</code> is your go-to. It runs after each render by default, but you can customize its behavior using a dependency array.</p>
<p>But you should consider using more specialized tools or libraries like React Query for event-based or render-based side effects.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> React, { useState, useEffect } <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">DataFetcher</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [data, setData] = useState(<span class="hljs-literal">null</span>);

  useEffect(<span class="hljs-function">() =&gt;</span> {
    fetch(<span class="hljs-string">'https://api.example.com/data'</span>)
      .then(<span class="hljs-function">(<span class="hljs-params">response</span>) =&gt;</span> response.json())
      .then(<span class="hljs-function">(<span class="hljs-params">data</span>) =&gt;</span> setData(data));
  }, []);  <span class="hljs-comment">// Empty dependency array means it runs once on mount</span>

  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>{data ? JSON.stringify(data) : 'Loading...'}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>;
}
</code></pre>
<p><strong>Code explanation</strong>: The <code>useEffect</code> hook fetches data when the component mounts. The effect will only run one time when the array is empty.</p>
<p><strong>2.</strong> <code>useLayoutEffect</code><br><code>useLayoutEffect</code> works similarly to <code>useEffect</code> but runs synchronously right after the DOM has been updated. It’s used for operations that need to happen before the browser paints the UI, like measuring elements.</p>
<p>Use it sparingly, as it runs less frequently than <code>useEffect</code>. Here’s an example:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> React, { useLayoutEffect, useRef } <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">Measure</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> divRef = useRef();

  useLayoutEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-built_in">console</span>.log(divRef.current.getBoundingClientRect());
  }, []);

  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">ref</span>=<span class="hljs-string">{divRef}</span>&gt;</span>Measure me!<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>;
}
</code></pre>
<p><strong>Code explanation</strong>: <code>useLayoutEffect</code> measures DOM elements before the browser repaints.</p>
<p><strong>3.</strong> <code>useInsertionEffect</code><br>Exclusively for CSS-in-JS library developers, <code>useInsertionEffect</code> runs before <code>useEffect</code> and <code>useLayoutEffect</code> to ensure that CSS styles are inserted properly. It’s niche, but crucial for maintaining style integrity in complex applications.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> React, { useInsertionEffect, useState } <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">StyledComponent</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [text, setText] = useState(<span class="hljs-string">'Hover over me!'</span>);

  useInsertionEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> style = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">'style'</span>);
    style.textContent = <span class="hljs-string">`
      .hovered {
        color: red;
        font-size: 24px;
        transition: color 0.3s ease;
      }
    `</span>;
    <span class="hljs-built_in">document</span>.head.appendChild(style);

    <span class="hljs-keyword">return</span> <span class="hljs-function">() =&gt;</span> {
      <span class="hljs-built_in">document</span>.head.removeChild(style);
    };
  }, []);

  <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">"hovered"</span>
      <span class="hljs-attr">onMouseEnter</span>=<span class="hljs-string">{()</span> =&gt;</span> setText('You hovered over me!')}
      onMouseLeave={() =&gt; setText('Hover over me!')}
    &gt;
      {text}
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<p><strong>Code explanation</strong>: The <code>useInsertionEffect</code> hook is used to inject styles into the DOM at runtime, making the component’s styling dynamic and scoped only to that component.</p>
<h3 id="heading-ref-hook"><strong>Ref Hook</strong></h3>
<p>1. <code>useRef</code><br><code>useRef</code> allows you to persist values across renders without causing re-renders. It's perfect for storing mutable values or referencing DOM elements. Whether you’re handling intervals, storing a DOM node, or keeping track of the previous state, <code>useRef</code> has you covered.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> React, { useRef } <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">FocusInput</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> inputRef = useRef(<span class="hljs-literal">null</span>);

  <span class="hljs-keyword">const</span> handleFocus = <span class="hljs-function">() =&gt;</span> {
    inputRef.current.focus();
  };

  <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">input</span> <span class="hljs-attr">ref</span>=<span class="hljs-string">{inputRef}</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handleFocus}</span>&gt;</span>Focus Input<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><strong>Code explanation:</strong> This React code uses <code>useRef</code> to create a reference to an input element. When the button is clicked, the <code>handleFocus</code> function triggers the input field to gain focus using <code>inputRef.current.focus()</code>.</p>
<h3 id="heading-performance-hooks"><strong>Performance Hooks</strong></h3>
<p><strong>1.</strong> <code>useMemo</code><br>For optimizing performance, <code>useMemo</code> is your friend. It caches the results of expensive computations and only recalculates when dependencies change. This can significantly improve performance, especially in scenarios involving heavy calculations.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> React, { useState, useMemo } <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">ExpensiveCalculation</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">const</span> expensiveComputation = useMemo(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">return</span> count * <span class="hljs-number">100</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>Expensive Computation: {expensiveComputation}<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;Increase Count<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><strong>Code explanation:</strong>This React code uses <code>useMemo</code> to optimize an expensive calculation (<code>count * 100</code>). The calculation only re-runs when <code>count</code> changes. The button increments <code>count</code>, triggering a UI update with the new result.</p>
<p><strong>2.</strong> <code>useCallback</code><br><code>useCallback</code> is similar to <code>useMemo</code>, but it focuses on memoizing callback functions. This is useful for preventing unnecessary re-renders of child components by keeping functions stable across renders.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> React, { useState, useCallback } <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">Child</span>(<span class="hljs-params">{ onClick }</span>) </span>{
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{onClick}</span>&gt;</span>Click me<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></span>;
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Parent</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">const</span> handleClick = useCallback(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Clicked'</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">Child</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handleClick}</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">{()</span> =&gt;</span> setCount(count + 1)}&gt;Increase Count<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><strong>Code explanation:</strong> This React code uses <code>useCallback</code> to memoize the <code>handleClick</code> function, preventing re-creation on every render. The <code>Child</code> component uses this function for its button. The parent updates <code>count</code> independently.</p>
<h3 id="heading-context-hook"><strong>Context Hook</strong></h3>
<p>1. <code>useContext</code><br>The <code>useContext</code> hook simplifies accessing context values. It reads the value from the nearest context provider and works seamlessly across nested components. This makes it easier to manage global states or themes.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> React, { useContext, createContext } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-keyword">const</span> ThemeContext = createContext(<span class="hljs-string">'light'</span>);

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ThemedButton</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> theme = useContext(ThemeContext);
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">button</span>&gt;</span>{theme}<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></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">ThemeContext.Provider</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"dark"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">ThemedButton</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">ThemeContext.Provider</span>&gt;</span></span>
  );
}
</code></pre>
<p><strong>Code explanation</strong>: This React code uses <code>createContext</code> to create a <code>ThemeContext</code>. <code>useContext</code> accesses the context value, displaying it in the button. The <code>App</code> component provides "dark" as the theme to <code>ThemedButton</code>.</p>
<h3 id="heading-transition-hook"><strong>Transition Hook</strong></h3>
<p>1. <code>useTransition</code><br><code>useTransition</code> lets you mark specific state updates as low-priority, enhancing the user experience by keeping the app more responsive during intensive computations or transitions. This improves the user experience by making the app more responsive.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> React, { useState, useTransition } <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">TransitionComponent</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">const</span> [isPending, startTransition] = useTransition();

  <span class="hljs-keyword">const</span> handleClick = <span class="hljs-function">() =&gt;</span> {
    startTransition(<span class="hljs-function">() =&gt;</span> {
      setCount(<span class="hljs-function">(<span class="hljs-params">prevCount</span>) =&gt;</span> prevCount + <span class="hljs-number">1</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">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handleClick}</span>&gt;</span>Increase Count<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      {isPending ? <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Loading...<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>Count: {count}<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><strong>Code explanation:</strong> This code uses <code>useTransition</code> to increment <code>count</code> without blocking the UI. While the state updates, <code>isPending</code> shows "Loading...". Clicking the button triggers a smooth, non-blocking state transition.</p>
<h3 id="heading-some-random-hooks"><strong>Some Random Hooks</strong></h3>
<p><strong>1.</strong> <code>useDeferredValue</code><br>Similar to <code>useTransition</code>, <code>useDeferredValue</code> helps in deferring state updates to keep the app responsive. It schedules updates to happen at an optimal time, enhancing the user experience without manual intervention.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> React, { useState, useDeferredValue } <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">DeferredComponent</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [value, setValue] = useState(<span class="hljs-string">''</span>);
  <span class="hljs-keyword">const</span> deferredValue = useDeferredValue(value);

  <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">input</span> <span class="hljs-attr">value</span>=<span class="hljs-string">{value}</span> <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setValue(e.target.value)} /&gt;
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Deferred Value: {deferredValue}<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><strong>Code explanation</strong>: <code>useDeferredValue</code> delays the update of <code>deferredValue</code> to ensure that the UI remains responsive.</p>
<p><strong>2.</strong> <code>useDebugValue</code><br><code>useDebugValue</code> is a hook primarily for debugging. It lets you label custom hooks in React DevTools, making it easier to track and debug your hooks.</p>
<pre><code class="lang-jsx">
<span class="hljs-keyword">import</span> React, { useDebugValue, useState } <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">useCustomHook</span>(<span class="hljs-params">value</span>) </span>{
  useDebugValue(value ? <span class="hljs-string">"Has Value"</span> : <span class="hljs-string">"No Value"</span>); <span class="hljs-keyword">return</span> value; }
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">DebugComponent</span>(<span class="hljs-params"></span>) </span>{ <span class="hljs-keyword">const</span> [value, setValue] = useState(<span class="hljs-string">''</span>); <span class="hljs-keyword">const</span> customValue = useCustomHook(value);

<span class="hljs-keyword">return</span> (
 <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">value</span>=<span class="hljs-string">{value}</span> <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setValue(e.target.value)} /&gt;</span>
Value: {customValue}
); }
</code></pre>
<p><strong>Code explanation:</strong> This code uses <code>useDebugValue</code> to show "Has Value" or "No Value" in React DevTools based on <code>value</code>. <code>useCustomHook</code> is used in <code>DebugComponent</code> to track the input state and display it dynamically.</p>
<p><strong>3.</strong> <code>useId</code><br><code>useId</code> generates unique IDs for elements, ensuring that form inputs and labels are properly linked without conflicts. It’s particularly useful when dealing with dynamically repeated elements.</p>
<pre><code class="lang-javascript">
<span class="hljs-keyword">import</span> React, { useId } <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">FormComponent</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> id = useId();

  <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">htmlFor</span>=<span class="hljs-string">{id}</span>&gt;</span>Name: <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">id</span>=<span class="hljs-string">{id}</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<p><strong>Code explanation</strong>: <code>useId</code> ensures that form elements have unique IDs, avoiding potential conflicts.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>React hooks can seem overwhelming at first, but with this guide, you’re well-equipped to handle them. Mastering these hooks improves your React skills and makes your development process smoother and more efficient.</p>
<p>For a deeper dive and hands-on practice, check out my comprehensive React Bootcamp, where you’ll find interactive challenges, videos, and cheat sheets to reinforce your knowledge.</p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
