<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Pranay Bajracharya</title>
    <description>The latest articles on DEV Community by Pranay Bajracharya (@pranay_bajracharya_11254b).</description>
    <link>https://dev.to/pranay_bajracharya_11254b</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2942211%2F71db0d29-943b-44f8-86c8-8ed73a6e8e83.jpg</url>
      <title>DEV Community: Pranay Bajracharya</title>
      <link>https://dev.to/pranay_bajracharya_11254b</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/pranay_bajracharya_11254b"/>
    <language>en</language>
    <item>
      <title>Debounce Control: React component to debounce state</title>
      <dc:creator>Pranay Bajracharya</dc:creator>
      <pubDate>Fri, 14 Mar 2025 11:56:38 +0000</pubDate>
      <link>https://dev.to/pranay_bajracharya_11254b/debounce-control-react-component-to-debounce-state-295a</link>
      <guid>https://dev.to/pranay_bajracharya_11254b/debounce-control-react-component-to-debounce-state-295a</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgtgd03mjd9x38kxex12p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgtgd03mjd9x38kxex12p.png" alt="DebounceControl Component" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What is debounce? Debounce is a way to delay a function until an action stops. For example, in a search bar, instead of running a search every time you press a key, debouncing waits until you finish typing, then runs the search just once. This keeps the app fast by avoiding too many repeated actions.&lt;/p&gt;

&lt;p&gt;But we already have a way to debounce state either using hook libraries like &lt;code&gt;useDebounce&lt;/code&gt; or creating your own. So, why do we need this?&lt;/p&gt;

&lt;p&gt;Let’s step back and see how &lt;code&gt;useDebounce&lt;/code&gt; work:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React, { useState } from "react";
import { useDebounce } from "some-where";

const App = () =&amp;gt; {
  const [text, setText] = useState("");

  const debouncedText = useDebounce(text, 1000); // 1000ms

  // do something with this `debouncedText`

  return (
    &amp;lt;input
      type="text"
      value={text}
      onChange={(e) =&amp;gt; setText(e.target.value)}
    /&amp;gt;
  );
};

export default App;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With each keystroke, we update the state with &lt;code&gt;setText&lt;/code&gt;, and when the user stops typing for 1000ms, &lt;code&gt;debouncedText&lt;/code&gt; finally updates. Ideally, this is when we’d make an API call.&lt;/p&gt;

&lt;p&gt;Now, here’s the problem: even though &lt;code&gt;debouncedText&lt;/code&gt; only updates once, the &lt;code&gt;text&lt;/code&gt; state still updates on each keystroke, causing the entire app to re-render on every input. This might not be an issue in this example, where we're just rendering a simple input element.&lt;/p&gt;

&lt;p&gt;Lets take a real world example:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fv2%2Fresize%3Afit%3A1400%2Fformat%3Awebp%2F1%2AI49O0rMcJ0EgzFjpuTW6-g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fv2%2Fresize%3Afit%3A1400%2Fformat%3Awebp%2F1%2AI49O0rMcJ0EgzFjpuTW6-g.png" alt="An example why we need DebounceControl" width="800" height="544"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The code might look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React, { useState } from "react";
import { useQuery } from 'react-query';
import { useDebounce } from "some-where";

const UserListPage = () =&amp;gt; {
  const [state, setState] = useState(initialState);

  const debouncedState = useDebounce(state, 1000); // 1000ms

  const { data } = useQuery({
    queryKey: ['user', debouncedState],
    queryFn: () =&amp;gt; fetchUserList(debouncedState),
  });

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;UserFilter state={state} setState={setState} /&amp;gt;
      &amp;lt;UserList data={data} /&amp;gt;
    &amp;lt;/div&amp;gt;
  );
};

export default UserListPage;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, do you see the problem? On each keystroke in any of the input fields, everything has to re-render, including the &lt;code&gt;UserList&lt;/code&gt; component, even though nothing related to it has changed.&lt;/p&gt;

&lt;p&gt;Now, this is where &lt;code&gt;&amp;lt;DebounceControl /&amp;gt;&lt;/code&gt; comes into play.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React, { useState } from "react";
import DebounceControl from "debounce-control";

const App = () =&amp;gt; {
  const [text, setText] = useState("");

  const onDebouncedChange = (value) =&amp;gt; {
    setText(value);
  }

  return (
    &amp;lt;DebounceControl
      value={text}
      delay={1000}
      onDebouncedChange={onDebouncedChange}
      render={({ value, onChange }) =&amp;gt; (
        &amp;lt;input
          type="text"
          value={value}
          onChange={(e) =&amp;gt; onChange(e.target.value)}
        /&amp;gt;
      )}
    /&amp;gt;
  );
};

export default App;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice how &lt;code&gt;DebounceControl&lt;/code&gt; decouples the debouncing logic from the rest of the app. With this, the &lt;code&gt;text&lt;/code&gt; state only updates after debouncing occurs, and in the previous example, the &lt;code&gt;UserList&lt;/code&gt; or the entire component will no longer re-render on each keystroke.&lt;/p&gt;

&lt;p&gt;Big question now. Why should we use this?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Minimal re-renders&lt;/li&gt;
&lt;li&gt;Works with any form element (not limited to &lt;code&gt;input&lt;/code&gt; or &lt;code&gt;textarea&lt;/code&gt;). Also, the element is right there if you want to add a &lt;code&gt;ref&lt;/code&gt; or modify props.&lt;/li&gt;
&lt;li&gt;Type-safe&lt;/li&gt;
&lt;/ol&gt;

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

&lt;p&gt;&lt;strong&gt;Input component&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiw1a8eb5grdqr3jjff2e.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiw1a8eb5grdqr3jjff2e.gif" alt="High re-renders before use of DebounceControl" width="591" height="466"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmigw6sapyh5oq4wmxtfc.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmigw6sapyh5oq4wmxtfc.gif" alt="Minimal re-renders after use of DebounceControl" width="587" height="460"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Slider component&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh7pvmsdyv7lf6pg03vv6.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh7pvmsdyv7lf6pg03vv6.gif" alt="Use of DebounceControl with Slider Component" width="570" height="330"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Resizable component&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy7jnq1sowqnnc439sxoe.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy7jnq1sowqnnc439sxoe.gif" alt="Use of DebounceControl with Resizable Component" width="584" height="471"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NPM: &lt;a href="https://www.npmjs.com/package/debounce-control" rel="noopener noreferrer"&gt;https://www.npmjs.com/package/debounce-control&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conclusion:&lt;/strong&gt;&lt;br&gt;
By using &lt;code&gt;&amp;lt;DebounceControl /&amp;gt;&lt;/code&gt;, you can easily debounce any form element while keeping your app performant and type-safe.&lt;/p&gt;

</description>
      <category>react</category>
      <category>debounce</category>
      <category>nextjs</category>
      <category>npm</category>
    </item>
  </channel>
</rss>
