Why ChatGPT (+ many tutorials) are wrong about React & debounce
I needed to implement debounce. I recalled seeing a solution somewhere in our codebase. I’ve used copy’n’paste strategy, adjusted code to work in my use case, run the app and … it wasn’t working 🤔
What’s going on?
That’s how my story with debounce started. I’ve already implemented debounce dozen of times. Now, instead of writing it myself, I’ve copied “working” solution from codebase. But it didn’t make sense. I didn’t even think that current solution wasn’t working, so I started debugging my part…
Quick recap -> What’s debounce?
Debounce is used in several use cases. The most common are:
- search
- autocomplete
- loading options in dropdown The idea is simple. You don’t want to “spam” backend with multiple request when making search. Usually users type few characters or even whole words, then wait for results. You don’t want to make request for each keystroke. That’s when you need debounce. It’s deferred function call with twist. Debounce delays a function call until after a certain period of inactivity. Since image is 1000 words:
I guess usually you’d use lodash
. If you’re curious, that’s simple implementation.
(Lodash implementation provides more options like cancel
or flush
)
How to check if debounce is working (correctly 😉)?
The easiest way is, of course, to put console.log
everywhere 💃🕺
And if you’re working with network requests, then definitely check out Network
tab. If it doesn’t work, you’ll see waterfall.
Don’t worry. It’s going to be easy to spot if you got debounce working.
ChatGPT & every other tutorial 🙈
That’s the context. I wanted to make things clear. The real question of that blog post is why every tutorial ChatGPT got it wrong? 🤔
If you search for debounce + React, you’ll got something like this:
What’s wrong in that case?
There are basically 2 problems with that solution and they are mutually exclusive 😳
First of all, you probably are using controlled components(or at least I hope so). Then you’ll adapt that solution to your use case & you’ll see that … it’s not working. If you
The second problem is that you’re using uncontrolled components. If you’re aware of the difference between controlled vs. uncontrolled components, that’s great. Otherwise, you’re doomed. There will be the day. I’d argue that React main superpower is determinist state, also UI state. So playing with uncontrolled components is dangerous game. Throughout 9 years of working with React, uncontrolled components were the most common bugs I’ve seen. (That could also be the case that you use uncontrolled component & live happily 😬 Just understand the consequences.)
How to do it right?
The key to correct implementation is useMemo
. Due to React re-renders, every time the state changes, new function is created. We need to wrap our debounced function in useMemo
so that we’re reusing the same function.
In that simple case, we’re using arrow function. We define “sendRequest” function on the fly. Often we’ll have already defined function.
We’ll need to wrap it into useCallback
🙈 since we need to put sendRequest
to dependency list of useMemo
.
(They say it’s going to be simpler when “new React compiler” arrives 😎)
Is it harder to be junior dev in ChatGPT era?
Definitely, you can find tutorials about debounce & React that present correct solution. Still I’ve found most tutorials to be incorrect about debounce. Since LLM is trained on that enormous content, it’s quite obvious that’s going to provide wrong solution 😒
For me, LLMs & Copilots are great solutions. It’s increasing my productivity. It makes writing code an addition to solving problems. I’m just curious how that’s going to impact broader ecosystem. I’m really curious what’s the impact on junior devs. First-order consequence seems to be positive. Developers are more productive. Junior dev can implement more stuff with basic knowledge. And what about second-order consequences?