<?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>Forem: Gabe Ragland</title>
    <description>The latest articles on Forem by Gabe Ragland (@gabe_ragland).</description>
    <link>https://forem.com/gabe_ragland</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%2F39082%2F25b4a670-7554-486d-bf2f-0d8c0f27e32e.jpg</url>
      <title>Forem: Gabe Ragland</title>
      <link>https://forem.com/gabe_ragland</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/gabe_ragland"/>
    <language>en</language>
    <item>
      <title>How my dev tool did $16,285 in sales last month</title>
      <dc:creator>Gabe Ragland</dc:creator>
      <pubDate>Tue, 23 Feb 2021 20:37:36 +0000</pubDate>
      <link>https://forem.com/gabe_ragland/how-my-dev-tool-did-16-285-in-sales-last-month-20im</link>
      <guid>https://forem.com/gabe_ragland/how-my-dev-tool-did-16-285-in-sales-last-month-20im</guid>
      <description>&lt;p&gt;Hey Dev.to community,&lt;/p&gt;

&lt;p&gt;I thought I'd share my experience launching my dev tool (&lt;a href="https://divjoy.com" rel="noopener noreferrer"&gt;divjoy.com&lt;/a&gt;) on Product Hunt last month. It ended up resulting in my best month ever at &lt;strong&gt;$16,265 in sales&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;For context, I've included a chart below with my entire traffic/sales history, including product milestones. As you can see, the Product Hunt launch led to a large sales spike (~250% higher than the previous month) and this month is shaping up to be around 30% higher than normal.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2F2u7nialpsui8h9j97tm0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F2u7nialpsui8h9j97tm0.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2u7nialpsui8h9j97tm0.png" rel="noopener noreferrer"&gt;High-res version&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this post I'm going to talk about how I optimized my launch, what worked, what I would do differently next time, and what's next for Divjoy. Okay, let's get into it 🤘&lt;/p&gt;

&lt;h3&gt;
  
  
  ⚛️ The product
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://divjoy.com" rel="noopener noreferrer"&gt;Divjoy&lt;/a&gt; is a tool that allows you to generate a custom Node + React codebase with everything you need for your next project like authentication, database, subscription payments, marketing pages, forms, account settings, etc. Everything works out of the box.&lt;/p&gt;

&lt;p&gt;Unlike most templates or boilerplates, Divjoy allows you to customize your technical options and template in a low-code editor before downloading your codebase. That means you get exactly what you need, nothing you don't, and you can get right to working on your actual product (you know, the fun part!).&lt;/p&gt;

&lt;p&gt;The main feature in this launch was Material UI integration. That meant in addition to supporting the Bulma and Bootstrap CSS frameworks, you could now have your entire front-end built using Material UI.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fxirk05i0l7guzh45skl0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fxirk05i0l7guzh45skl0.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  🤔 Launch planning
&lt;/h3&gt;

&lt;p&gt;Planning an effective Product Hunt launch involves getting together the copy/media you need to make your launch interesting and ensuring you're leveraging any existing audiences or connections to amplify your launch. I highly recommend starting a brainstorm doc at least a month in advance.&lt;/p&gt;

&lt;p&gt;There are no shortage of launch checklists on the web, but it's a mistake to think you can just quickly go through a checklist the day before. The devil is in the details. Get a doc up and periodically jot down any ideas you have, ranging from practical to "I'll probably think this is dumb in the morning".&lt;/p&gt;

&lt;p&gt;By starting early I was able to ...&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Find an awesome designer to do an &lt;a href="https://www.producthunt.com/posts/divjoy-2-0" rel="noopener noreferrer"&gt;animated logo&lt;/a&gt; for me.&lt;/li&gt;
&lt;li&gt;Figure out an unconventional plan for getting hundreds of readers on &lt;a href="https://usehooks.com" rel="noopener noreferrer"&gt;usehooks.com&lt;/a&gt; to support the launch.&lt;/li&gt;
&lt;li&gt;Realize I actually needed to increase the scope beyond Material UI if I wanted to call this "Divjoy 2.0". This became obvious as I was planning out my pitch. I ended up pushing back the launch 2 weeks, adding betters docs, a members-only Discord community, and an interactive data component.&lt;/li&gt;
&lt;li&gt;Figure out a good launch day pricing strategy. I decided to bump up my price from $99 to $149, but I kept the launch day price at $99 "for the next 24 hours". This ended up working well because.. well FOMO, but it also allowed to me get existing customers to support the launch without them feeling like they overpaid.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  🌘 Launch Day (well actually night)
&lt;/h3&gt;

&lt;p&gt;I submitted Divjoy 2.0 to &lt;a href="https://www.producthunt.com/posts/divjoy-2-0" rel="noopener noreferrer"&gt;Product Hunt&lt;/a&gt; right after midnight (PST) on January 14th. The earlier you submit the more time your product has to climb the rankings before the front page resets.&lt;/p&gt;

&lt;p&gt;At this point I was exhausted and hadn't yet written my launch announcements for Twitter and my customer mailing list. I was planning on writing them earlier that day, but it was a push to get everything ready and it somehow slipped my mind. Whoops. About 2 minutes after launching I could see other products climbing up the rankings and Divjoy was dead last. I finally managed to muster enough brain energy to get a &lt;a href="https://twitter.com/gabe_ragland/status/1349648629896675330" rel="noopener noreferrer"&gt;tweet&lt;/a&gt; out. It wasn't a great tweet, but it did the job. I could see people I knew from Twitter dropping upvotes/comments and I could see Divjoy slowly moving upwards. Okay, time to get some sleep 😴&lt;/p&gt;

&lt;p&gt;I woke up the next morning with Divjoy at #5. Wow, much better than expected. The rest of the day was about leveraging my existing audience and connections to keep the momentum going. Here's everything I did:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Emailed all Divjoy customers, letting them know about the new features and asking for their support on the Product Hunt launch.&lt;/li&gt;
&lt;li&gt;Emailed a couple hundred Divjoy customers that were on an old yearly plan, letting them know I was upgrading them to a lifetime account for free. Since I had moved entirely to lifetime pricing I was planning on doing this anyway, but waiting until launch day allowed me to channel this good will towards the launch.&lt;/li&gt;
&lt;li&gt;Emailed my 7,454 usehooks.com subscribers with a &lt;a href="https://usehooks.com/useKonamiCode/" rel="noopener noreferrer"&gt;tutorial&lt;/a&gt; on how to build a useKonamiCode React hook. In order to see an example of it in action they had to head over to &lt;a href="https://divjoy.com" rel="noopener noreferrer"&gt;divjoy.com&lt;/a&gt; and enter the famous Konami code. A lot of those visitors went on to click the Product Hunt launch announcement at the top of the website.&lt;/li&gt;
&lt;li&gt;Made sure to reply to everyone to PH and Twitter. A fun side-effect of the Konami code easter egg was people started &lt;a href="https://twitter.com/irtimid_harding/status/1349788819269316611" rel="noopener noreferrer"&gt;tweeting about it&lt;/a&gt;, I could retweet those, driving more interest in checking it out, and so on. Lesson: Try something fun/different that helps your launch stand out.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the end, I managed to make it to the #3 product of the day and I'm really happy with how it turned out.  It's hard to say exactly how much all my outreach efforts above helped. I'd guess around a 30% boost? Your success on Product Hunt is mostly going to come down to whether the community finds it interesting. That said, if you have any audience at all, it's worth thinking about how you can engage with them on launch day to give yourself the best chance possible.&lt;/p&gt;

&lt;p&gt;I was surprised to see the Product Hunt page continue to drive traffic/sales over the next few weeks, ending the month at $16,265 total, with $10,452 directly attributable to the launch.&lt;/p&gt;

&lt;h3&gt;
  
  
  😬  What I would do differently next time
&lt;/h3&gt;

&lt;p&gt;My biggest mistake was not preparing my tweet and email content ahead of time. If you're going to launch right after midnight (which I recommend) then you're going to be tired and winging all this isn't the best idea. My outreach spanned most of launch day, when ideally it could have all gone out right after midnight.&lt;/p&gt;

&lt;h3&gt;
  
  
  🌈  What's next?
&lt;/h3&gt;

&lt;p&gt;So far my strategy has been to spend 90% of my time coding and 10% being active on Twitter, Indie Hackers, etc.. with a big launch announcement every 3-4 months. Basically, spend as much time possible building while doing the minimum to keep sales up. That's what I'm most comfortable with. But my goal for 2021 is to do &lt;strong&gt;$100k in sales&lt;/strong&gt; and that means finding more scalable marketing channels. That means getting my SEO game together, trying out paid advertising, and spending more time looking for affiliate partners. I still have a lot of product improvements planned for 2021, but maybe it will need to be more like 50% coding and 50% marketing. It's time to get comfortable with that.&lt;/p&gt;

&lt;p&gt;I hope you found this write-up interesting and that it helps inform your next launch. Feel free to ask me anything in the comments below.&lt;/p&gt;

&lt;p&gt;Useful links&lt;br&gt;
🔗 &lt;a href="https://twitter.com/gabe_ragland" rel="noopener noreferrer"&gt;twitter.com/gabe_ragland&lt;/a&gt; —  follow my startup journey 👀&lt;br&gt;
🔗 &lt;a href="https://divjoy.com?promo=devto" rel="noopener noreferrer"&gt;divjoy.com?promo=devto&lt;/a&gt; — 30% off, valid for next 24 hours 😘&lt;/p&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>jamstack</category>
    </item>
    <item>
      <title>How to create a useKonamiCode React hook 🎮</title>
      <dc:creator>Gabe Ragland</dc:creator>
      <pubDate>Fri, 15 Jan 2021 19:26:25 +0000</pubDate>
      <link>https://forem.com/gabe_ragland/how-to-create-a-usekonamicode-react-hook-259a</link>
      <guid>https://forem.com/gabe_ragland/how-to-create-a-usekonamicode-react-hook-259a</guid>
      <description>&lt;p&gt;This hook makes it easy to fire off a function when the visitor enters the Konami Code on their keyboard (&lt;strong&gt;↑ ↑ ↓ ↓ ← → ← → B A&lt;/strong&gt;). Every web app needs a cheat code right? Read through the code comments below to see how it works. Want to try it out? I'm using this hook in production on &lt;a href="https://divjoy.com"&gt;divjoy.com&lt;/a&gt;. Head over there, enter the code, and something amazing will happen. You won't regret it 😻&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Usage&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
  &lt;span class="c1"&gt;// Call hook with function to fire off  &lt;/span&gt;
  &lt;span class="c1"&gt;// after konami code is entered.&lt;/span&gt;
  &lt;span class="nx"&gt;useKonamiCode&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Good job 🥳&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="c1"&gt;// Render whatever you like&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      Can you find the easter egg?
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;useKonamiCode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// State to hold array of recently pressed keys&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setKeys&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;([]);&lt;/span&gt;

  &lt;span class="c1"&gt;// Convert stored keys to string and match against konami code string&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isKonamiCode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt; &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;up up down down left right left right B A&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nx"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// When a key is pressed&lt;/span&gt;
    &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onkeydown&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// Update array of keys in state with new key&lt;/span&gt;
      &lt;span class="nx"&gt;setKeys&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;currentKeys&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;currentKeys&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;getKeyName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;keyCode&lt;/span&gt;&lt;span class="p"&gt;)]);&lt;/span&gt;

      &lt;span class="c1"&gt;// Clear 5s timeout since key was just pressed&lt;/span&gt;
      &lt;span class="nx"&gt;clearTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="c1"&gt;// Reset keys if 5s passes so user can try again&lt;/span&gt;
      &lt;span class="nx"&gt;timeout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;setKeys&lt;/span&gt;&lt;span class="p"&gt;([]),&lt;/span&gt; &lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;

  &lt;span class="c1"&gt;// Once konami code is entered call handler function&lt;/span&gt;
  &lt;span class="c1"&gt;// and reset keys so user can do it again.&lt;/span&gt;
  &lt;span class="nx"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isKonamiCode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="nx"&gt;setKeys&lt;/span&gt;&lt;span class="p"&gt;([]);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;isKonamiCode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;isKonamiCode&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getKeyName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;keyCode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="mi"&gt;37&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;left&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="mi"&gt;38&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;up&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="mi"&gt;39&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;right&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;down&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="mi"&gt;65&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;A&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="mi"&gt;66&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;B&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;}[&lt;/span&gt;&lt;span class="nx"&gt;keyCode&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you've got nothing stopping you from adding the Konami Code to your React app. If you do, be sure to share a link in the comments ⤵️&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>react</category>
    </item>
    <item>
      <title>How my dev tool made $10,041 in 4 days</title>
      <dc:creator>Gabe Ragland</dc:creator>
      <pubDate>Wed, 15 Jul 2020 18:18:36 +0000</pubDate>
      <link>https://forem.com/gabe_ragland/how-my-dev-tool-made-10-041-in-4-days-28ac</link>
      <guid>https://forem.com/gabe_ragland/how-my-dev-tool-made-10-041-in-4-days-28ac</guid>
      <description>&lt;p&gt;Hey Dev.to community,&lt;/p&gt;

&lt;p&gt;I just wanted to share how a recent feature launch for my dev tool (&lt;a href="https://divjoy.com"&gt;divjoy.com&lt;/a&gt;) ended up making $10,041 in 4 days. That's more than its earned in the previous 4 months! What's more, this happened in entirely on Twitter.  I'll be talking about some things I learned, pricing insights, as well as tactics for launching on Twitter and keeping the hype going for multiple days. Okay, let's do this ⛷&lt;/p&gt;

&lt;h3&gt;
  
  
  ⚛️ The product
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://divjoy.com"&gt;Divjoy&lt;/a&gt; is tool that allows you to generate a custom Node + React codebase with everything you need for your next project like authentication, database, subscription payments, marketing pages, forms, account settings, etc. Everything works out of the box.&lt;/p&gt;

&lt;p&gt;Unlike most templates or boilerplates, Divjoy allows you to customize your technical options and template in a low-code editor before downloading your codebase. That means you get exactly what you need, nothing you don't, and you can get right to working on your actual product (you know, the fun part!).&lt;/p&gt;

&lt;h3&gt;
  
  
  🤔 Launch planning
&lt;/h3&gt;

&lt;p&gt;The feature I launched was &lt;strong&gt;Stripe payments integration&lt;/strong&gt;. This was a big step for the product because it meant that customers would now be able to export a complete SaaS app. Just export your code, add some environment variables, and you've got a functioning web app with pricing page, Stripe payments flow, customer billing management, webhooks, and everything else you need.&lt;/p&gt;

&lt;p&gt;I knew there was a good number of people waiting on this feature, but I really wanted to do everything I could to ensure the launch was a success. Frankly, being a solo-founder is tough and I knew that I needed more than a small uptick in sales from this to keep my enthusiasm and productivity going strong. &lt;/p&gt;

&lt;p&gt;After some lively debate between me and my dog (what can I say, this whole pandemic thing is getting to me), I decided to combine the launch with an awesome lifetime deal. For $49 you'd get access to Divjoy for life. That's less then the normal yearly price! Maybe I went a bit overboard on the discount, but I decided it was better to hedge my bets on a successful launch even if it meant leaving money on the table.&lt;/p&gt;

&lt;p&gt;In terms of where and how to launch, that honestly didn't require too much planning. My entire audience is on Twitter and I know Twitter well. My plan was to post an announcement tweet in the morning and periodically update the thread throughout the day with product details and launch stats (more on this tactic later).&lt;/p&gt;

&lt;p&gt;The last thing I did was add an announcement to the homepage:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lc_h4zh9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/g1mhxqiqnvwb9uhu4r1x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lc_h4zh9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/g1mhxqiqnvwb9uhu4r1x.png" alt="homepage"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And update the pricing section to show the deal:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xKTPegKF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/w2v6p8qrp2jde9ohdm6e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xKTPegKF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/w2v6p8qrp2jde9ohdm6e.png" alt="pricing section"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  ☀️ Launch day
&lt;/h3&gt;

&lt;p&gt;The launch started with a &lt;a href="https://twitter.com/gabe_ragland/status/1278786262816583681"&gt;single tweet&lt;/a&gt; on Thursday, July 2nd.  Here's a screenshot + some tips for a successful feature launch tweet:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Z4Chw2tp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/h1yoj7qr2pzrttlopjo7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Z4Chw2tp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/h1yoj7qr2pzrttlopjo7.png" alt="launch tweet with tips"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Likes and retweets started rolling in pretty quickly. Basically, my Twitter followers are awesome people and have made every single one of my launches successful. I really wouldn't be anywhere without their support ❤️&lt;/p&gt;

&lt;p&gt;The major difference this time was that sales were coming in quickly as well. In past feature launches I might see a couple hundred people hit the website and 5 extra sales that day, but this time I passed 5 sales within the first 20 minutes. And I hadn't even mentioned the deal yet...&lt;/p&gt;

&lt;p&gt;A little while later I added a new tweet to the thread, announcing the lifetime deal and some perks.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--iCmFV8Rt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/482c956nb17olnp54m4m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--iCmFV8Rt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/482c956nb17olnp54m4m.png" alt="deal tweet"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And sales started coming in even faster and continued at a steady pace over the next 48 hours. I continued to update &lt;a href="https://twitter.com/gabe_ragland/status/1278786262816583681"&gt;the thread&lt;/a&gt; over the course of the launch, but ending up spending the vast majority of that time answering support questions and giving new customers advice on how to extend their code. It was exhausting and hard to keep up.. but also really validating to see so many people hacking away on product ideas right after purchasing. That's the whole point! A lower barrier to entry means more people building that idea they've always wanted to build.&lt;/p&gt;

&lt;p&gt;By the time the deal ended Friday evening it had done $7,448, but I ended up extending through the weekend after waking up to a bunch of messages from people asking if it was too late.&lt;/p&gt;

&lt;h3&gt;
  
  
  📈The final results
&lt;/h3&gt;

&lt;p&gt;👀 The Twitter thread was viewed 127,384 times&lt;br&gt;
👋 Sending 2,619 people to &lt;a href="https://divjoy.com"&gt;divjoy.com&lt;/a&gt;&lt;br&gt;
💬 Resulting in 46 support chats and 9 screen-share sessions&lt;br&gt;
💸 Driving $10,041 in sales over 4 days&lt;/p&gt;

&lt;h3&gt;
  
  
  🤗 What worked
&lt;/h3&gt;

&lt;p&gt;I really really did not expect things to go so well and was honestly kind of baffled the whole time. After finally getting some good sleep Sunday night and reflecting on what happened I came up with a few thoughts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;There was pent up demand for Stripe integration&lt;/strong&gt;. A lot of people waiting to buy Divjoy wanted to build a SaaS product and now they finally could. I think it's also safe to assume that people building paid products are generally more willing to shell out some cash to speed things up.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The lifetime deal made it an easy decision&lt;/strong&gt;. Use Divjoy once at any point in the future and you've gotten your money's worth. Hell, even if you simply wanted to use it as a reference or see how I handle some specific edge case around auth or payments it's worth the $49.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The members-only community was appealing&lt;/strong&gt;, even though I only briefly  hinted at it &lt;a href="https://twitter.com/gabe_ragland/status/1278796497304186880"&gt;in one of my tweets&lt;/a&gt;. A good number of customers brought this up and it was clearly a factor in their purchasing decision. People need community now more than ever and I've got big plans for this.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;I kept the Twitter hype going&lt;/strong&gt;. By spacing out tweets in my &lt;a href="https://twitter.com/gabe_ragland/status/1278786262816583681"&gt;Twitter thread&lt;/a&gt; over 4 days I ensured that it would keep getting bumped to the top of people's newsfeeds. Periodic updates about how the launch was going created a fun story people could follow. Lastly, if &lt;a href="https://twitter.com/kilianvalkhof/status/1279050960581648384"&gt;someone&lt;/a&gt; &lt;a href="https://twitter.com/mdocter/status/1279533338076876800"&gt;tweeted&lt;/a&gt; &lt;a href="https://twitter.com/d__raptis/status/1279049353328558084"&gt;about&lt;/a&gt; &lt;a href="https://twitter.com/LashaKrikheli/status/1278995155991834624"&gt;how&lt;/a&gt; &lt;a href="https://twitter.com/zmarkan/status/1278997460397035520"&gt;they&lt;/a&gt; &lt;a href="https://twitter.com/hughdurkin/status/1279794167514832897"&gt;grabbed&lt;/a&gt; the &lt;a href="https://twitter.com/castillo__io/status/1279146470180974592"&gt;deal&lt;/a&gt; or &lt;a href="https://twitter.com/DBredvick/status/1278846524429152266"&gt;shared&lt;/a&gt; a &lt;a href="https://twitter.com/DaltonEdwards/status/1278843288259301376"&gt;testimonial&lt;/a&gt; I made sure to immediately retweet them. This is free publicity, shows people you appreciate their support, and the more you do it the more it encourages other people to buy and share.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  😬 What could have been better
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;I could have done a better job at showing videos of the product and Stripe integration. After someone asked, I quickly recording a &lt;a href="https://www.youtube.com/watch?v=xY6f6Xm-83M"&gt;video&lt;/a&gt;, but this could have been much better.&lt;/li&gt;
&lt;li&gt;I could have launched in more places (like Dev.to, Indie Hackers, and HN). I planned on doing this but never found the time with the sheer number of support requests coming in.&lt;/li&gt;
&lt;li&gt;If I had known it would blow up like this I'd have prioritized getting a really good FAQ in before the launch rather than later. Less time answering common questions would have freed me up for more important things.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  🌈 What's next?
&lt;/h3&gt;

&lt;p&gt;All in all I'm ecstatic about how the launch went. I was hoping to break $1,000 in sales and ended up doing 10x that. What more can I ask for? &lt;/p&gt;

&lt;p&gt;Since the launch I've spent most of my time talking to new customers and learning about what they're building. Over the next month I'm going to be focused on expanding the selection of templates/components, working on an improved onboarding flow, and finally getting my SEO game together.&lt;/p&gt;

&lt;p&gt;I hope you found this writeup interesting and that it helps inform your next launch. Feel free to drop any questions you have in the comments below.&lt;/p&gt;

&lt;h3&gt;
  
  
  Useful links
&lt;/h3&gt;

&lt;p&gt;🔗 &lt;a href="https://divjoy.com?promo=devto"&gt;divjoy.com?promo=devto&lt;/a&gt; (40% off deal for you)&lt;br&gt;
🔗 &lt;a href="https://twitter.com/gabe_ragland"&gt;twitter.com/gabe_ragland&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>node</category>
      <category>webdev</category>
      <category>startup</category>
    </item>
    <item>
      <title>Divjoy in 2019 and what's coming in 2020 🚀 </title>
      <dc:creator>Gabe Ragland</dc:creator>
      <pubDate>Tue, 21 Jan 2020 19:29:30 +0000</pubDate>
      <link>https://forem.com/gabe_ragland/divjoy-in-2019-and-what-s-coming-in-2020-3n0n</link>
      <guid>https://forem.com/gabe_ragland/divjoy-in-2019-and-what-s-coming-in-2020-3n0n</guid>
      <description>&lt;p&gt;&lt;a href="https://divjoy.com"&gt;Divjoy&lt;/a&gt; is a React codebase and UI generator that saves you weeks of development time when starting a new project.&lt;/p&gt;

&lt;p&gt;2019 was a great year for Divjoy. I launched it to the public on &lt;a href="https://news.ycombinator.com/item?id=20688044"&gt;Hacker News&lt;/a&gt; and had 15k people hit the site and over 5k people export React codebases in a single day. I added support for &lt;a href="https://divjoy.com/?framework=next"&gt;Next.js&lt;/a&gt; and &lt;a href="https://divjoy.com/?kit=bootstrap"&gt;React Bootstrap&lt;/a&gt;. I added a bunch of new components to the library based on feedback. I launched again on &lt;a href="https://www.producthunt.com/posts/divjoy-4"&gt;Product Hunt&lt;/a&gt;. I won a $15,000 grant from &lt;a href="https://blog.ycombinator.com/announcing-the-startup-school-2019-grant-recipients/"&gt;Startup School&lt;/a&gt; to support Divjoy's development. Finally, in order to grow this into a sustainable business, I started charging money for code export. People are paying and the future is looking bright! None of this would have been possible without the many many people who've given me feedback along the way and all the developers and open-source maintainers that have made the React-ecosystem what it is. So thank you all!&lt;/p&gt;

&lt;p&gt;🌈 &lt;strong&gt;What's in store for 2020:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Stripe integration&lt;/strong&gt;&lt;br&gt;
I'll be adding Stripe integration so that all the templates have a fully-functional payments flow right out of the box. Divjoy will automatically export all the backend logic needed to charge cards and handle webhooks.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Material UI support&lt;/strong&gt;&lt;br&gt;
I've gotten a ton of requests for Material UI. Over 500 people are signed up just to be notified when this lands. Rest assured it’s coming!&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Gatsby support&lt;/strong&gt;&lt;br&gt;
Many people have asked for Gatsby support and I'm excited to get it in this year. There's also some interesting potential to integrate with the Gatsby's data and plugin system.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Components, components, components!&lt;/strong&gt;&lt;br&gt;
I’m going to be focused on expanding the selection of components for the next couple of months. Things like user onboarding flows, accounts settings pages, dashboards, activity feeds, dynamic CRUD interfaces, searchable content lists, and so on. You'll be able to drop any of these into your app using our built-in editor and they'll just work.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Editor improvements&lt;/strong&gt;&lt;br&gt;
The built-in app editor definitely needs some love this year. The initial version was a bit of a crazy experiment. Could I build a drag and drop React UI builder that also allows direct editing of component code? Well, yes.. kind of, but the reality is most people want to do the code stuff after export. So the plan is to drastically simplify the interface by removing (or at least hiding) the more advanced features and focus on providing a really nice UI over things like component props, global styles, and data fetching.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Single component export&lt;/strong&gt;&lt;br&gt;
You’ll be able to browse our component library and export single components to drop into an existing codebase. Right now Divjoy is optimized for people who need a full codebase, but I'm going to make it an awesome tool for people who've already started and would like to grab what they need. Imagine being able to grab a &lt;code&gt;&amp;lt;Payments/&amp;gt;&lt;/code&gt; component that comes with all the necessary JS and server-side logic needed to make it functional. In less than 5 minutes you should be able to export code from Divjoy and add a new feature to your app.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;❤️ &lt;strong&gt;How you can help&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Help spread the word&lt;/strong&gt;&lt;br&gt;
If you’ve got friends starting a new React project soon let them know that Divjoy can save them a ton of time.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Send me your feedback&lt;/strong&gt;&lt;br&gt;
What do you like and dislike about Divjoy? What kind of components and templates would you like to see? I'd love to hear your thoughts and I always appreciate critical feedback. &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Have an awesome 2020 🌟&lt;/p&gt;

&lt;p&gt;Best,&lt;br&gt;
Gabe&lt;/p&gt;

</description>
      <category>react</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Debouncing with React Hooks</title>
      <dc:creator>Gabe Ragland</dc:creator>
      <pubDate>Thu, 17 Jan 2019 19:24:04 +0000</pubDate>
      <link>https://forem.com/gabe_ragland/debouncing-with-react-hooks-jci</link>
      <guid>https://forem.com/gabe_ragland/debouncing-with-react-hooks-jci</guid>
      <description>&lt;p&gt;Today I'm going to show you how to build a useDebounce React Hook that makes it super easy to debounce API calls to ensure that they don't execute too frequently. I've also put together a demo that uses our hook. It searches the Marvel Comic API and uses useDebounce to prevent API calls from being fired on every keystroke. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fbopmzzrdtelaqc198pww.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fbopmzzrdtelaqc198pww.gif" alt="demo screenshot"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Pretty nifty huh? Okay, now on to the code!&lt;/p&gt;

&lt;p&gt;First let's figure out how we want our hook to be used and we can let that guide or actual implementation of the hook logic. Rather than debounce the calling of our API request we're going to design this hook to debounce any value within our component's render function. We're then going to combine this with &lt;code&gt;useEffect&lt;/code&gt; to fire off a new API request whenever that input value changes. This code example assumes some familiarity with the &lt;code&gt;useState&lt;/code&gt; and &lt;code&gt;useEffect&lt;/code&gt; hooks, which you can learn about in the &lt;a href="https://reactjs.org/docs/hooks-intro.html" rel="noopener noreferrer"&gt;React Hook docs&lt;/a&gt;.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;useDebounce&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./use-debounce&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Usage&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// State and setter for search term&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;searchTerm&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setSearchTerm&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="c1"&gt;// State and setter for search results&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setResults&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;([]);&lt;/span&gt;
  &lt;span class="c1"&gt;// State for search status (whether there is a pending API request)&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;isSearching&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setIsSearching&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Now we call our hook, passing in the current searchTerm value.&lt;/span&gt;
  &lt;span class="c1"&gt;// The hook will only return the latest value (what we passed in) ...&lt;/span&gt;
  &lt;span class="c1"&gt;// ... if it's been more than 500ms since it was last called.&lt;/span&gt;
  &lt;span class="c1"&gt;// Otherwise, it will return the previous value of searchTerm.&lt;/span&gt;
  &lt;span class="c1"&gt;// The goal is to only have the API call fire when user stops typing ...&lt;/span&gt;
  &lt;span class="c1"&gt;// ... so that we aren't hitting our API rapidly.&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;debouncedSearchTerm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useDebounce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;searchTerm&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Here's where the API call happens&lt;/span&gt;
  &lt;span class="c1"&gt;// We use useEffect since this is an asynchronous action&lt;/span&gt;
  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// Make sure we have a value (user has entered something in input)&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;debouncedSearchTerm&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Set isSearching state&lt;/span&gt;
        &lt;span class="nf"&gt;setIsSearching&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="c1"&gt;// Fire off our API call&lt;/span&gt;
        &lt;span class="nf"&gt;searchCharacters&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;debouncedSearchTerm&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="c1"&gt;// Set back to false since request finished&lt;/span&gt;
          &lt;span class="nf"&gt;setIsSearching&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
          &lt;span class="c1"&gt;// Set results state&lt;/span&gt;
          &lt;span class="nf"&gt;setResults&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;setResults&lt;/span&gt;&lt;span class="p"&gt;([]);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="c1"&gt;// This is the useEffect input array&lt;/span&gt;
    &lt;span class="c1"&gt;// Our useEffect function will only execute if this value changes ...&lt;/span&gt;
    &lt;span class="c1"&gt;// ... and thanks to our hook it will only change if the original ...&lt;/span&gt;
    &lt;span class="c1"&gt;// value (searchTerm) hasn't changed for more than 500ms.&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;debouncedSearchTerm&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Pretty standard UI with search input and results&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt;
        &lt;span class="na"&gt;placeholder&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Search Marvel Comics"&lt;/span&gt;
        &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setSearchTerm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;

      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;isSearching&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Searching ...&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;

      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h4&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h4&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;img&lt;/span&gt;
            &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;thumbnail&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/portrait_incredible.&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;
              &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;thumbnail&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;extension&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// API search function&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;searchCharacters&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;search&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;apiKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;f9dfb1e8d466d36c27850bedd2047687&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;queryString&lt;/span&gt; &lt;span class="s2"&gt;`apikey=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;amp;titleStartsWith=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;search&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s2"&gt;`https://gateway.marvel.com/v1/public/comics?&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;queryString&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;GET&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;



&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Okay, so that looks pretty good! Now let's build the actual hook so that our app works.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Our hook&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;useDebounce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// State and setters for debounced value&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;debouncedValue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setDebouncedValue&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// Set debouncedValue to value (passed in) after the specified delay&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;setDebouncedValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="c1"&gt;// Return a cleanup function that will be called every time ...&lt;/span&gt;
      &lt;span class="c1"&gt;// ... useEffect is re-called. useEffect will only be re-called ...&lt;/span&gt;
      &lt;span class="c1"&gt;// ... if value changes (see the inputs array below). &lt;/span&gt;
      &lt;span class="c1"&gt;// This is how we prevent debouncedValue from changing if value is ...&lt;/span&gt;
      &lt;span class="c1"&gt;// ... changed within the delay period. Timeout gets cleared and restarted.&lt;/span&gt;
      &lt;span class="c1"&gt;// To put it in context, if the user is typing within our app's ...&lt;/span&gt;
      &lt;span class="c1"&gt;// ... search box, we don't want the debouncedValue to update until ...&lt;/span&gt;
      &lt;span class="c1"&gt;// ... they've stopped typing for more than 500ms.&lt;/span&gt;
      &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;clearTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="c1"&gt;// Only re-call effect if value changes&lt;/span&gt;
    &lt;span class="c1"&gt;// You could also add the "delay" var to inputs array if you ...&lt;/span&gt;
    &lt;span class="c1"&gt;// ... need to be able to change that dynamically.&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; 
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;debouncedValue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;



&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;And there you have it! We now have a debounce hook that we can use to debounce any value right in the body of our component. Debounced values can then be included in &lt;code&gt;useEffect&lt;/code&gt;'s input array, instead of the non-debounced values, to limit the frequency of that effect being called.&lt;/p&gt;

&lt;p&gt;Also check out my &lt;a href="https://divjoy.com?ref=devtodebounce" rel="noopener noreferrer"&gt;React codebase generator&lt;/a&gt;. It will give you a nice UI, auth, database, payments and more. Thousands of React devs use it to build and launch apps quickly.&lt;/p&gt;

</description>
      <category>react</category>
      <category>hooks</category>
      <category>debounce</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
