So this is a basic not-taking app. Oops! Oh, wait! Oh, no! I—I, hold on. Sorry. I— This. Yes. Ah! Yes, we're back. So this is a basic not-taking app, and it has a list of nodes which you can filter. And if you try to filter these nodes, the app will get slow. You can notice it if you look at this cube of ice that spins. It's a spinner that freezes when the app freezes, when the page freezes, and, well, spins when it's not frozen, kind of like opposite of ice.
If I try typing, if I try filtering nodes, if I try typing the F letter, for example, you can notice how the spinner freezes for a second or two. If I try typing more, you could see how the app just lags as I'm typing. So you can't really feel it, because I'm typing behind the keyboard. But you could see how I'm typing, and the app feels really, really slow. The UI updates, happens with the delay, and the app just freezes for a second or two.
So now, whenever I have a performance issue, what I like to do is I like to open DevTools Profiler, DevTools Performance, and try to record what's happening in the app with the performance pane. So in this case, if I click record, and try typing, and stop recording, I'll see that what's happening in the app is I have this huge 500ms spike of CPU activity, and if I zoom into that spike of CPU activity, I'll see that I have a single keydown event that takes 550ms to process, and underneath that event, there are a whole lot of React function calls.
So now, if I were to debug this a little deeper and try to figure out what's going on, I would see this. So here's what happens in the app. What happens is I'm typing into the text field, the filter inputs, that calls this set filter function, which is just a useState hook, that, in turn, changes the state in a bunch of components, and that causes React to render all these components one by one until it's done. And because we have a lot of components, a lot of node buttons, that takes a while. So this re-render is a stop-the-world operation. Nothing can happen until React is done. If a user tries to interact with the app in any way, they'll have to wait until the re-render is done. If re-rendering the app takes two seconds, the user will have to wait for two seconds. This is how React 17 works, React 16 works, even React 18 works out of the box. A pretty standard JavaScript blocking behavior.
Now, let's take a step back. We have a performance issue, right? I'm typing to the text field, and that text field goes to a list of nodes to re-render, and this re-render is blocking and expensive, which slows the app and slows the whole typing process. So my question to you, to you folks, if you were a developer of this app, and this app was using React 17, how would you try to solve this? There are multiple solutions here, what would you try? Sorry? De-balancing.
Comments