React Concurrency × Core Web Vitals

Rate this content
Bookmark
This talk comes with bad news. Google has launched a new metric – INP – which measures how fast page interactions are. This metric becomes a Core Web Vital in Mar 2024 – and pretty much every React app Ivan has seen so far has this metric way in red.

The good news is React 18 shipped new features that help to solve this – notably, useTransition() and Suspense. And in this talk, we’ll look at how exactly these features work, what they do, and how we can use them to make INP green.
26 min
13 Nov, 2023

AI Generated Video Summary

The Talk discusses the InteractionToNextPaint metric, which measures the speed of clicks or keyboard inputs on a page. It explores the impact of slow interactions and slow React renders on user experience. The Talk also covers optimization techniques for React rendering, including the use of concurrent features and the StartTransition function. React 18 introduces changes to the rendering process that improve interaction speed. Concurrent rendering and suspense boundaries are highlighted as features that can enhance the performance of React apps.

1. Introduction to InteractionToNextPaint metric

Short description:

The PageSpeed Insights report for newyorktimes.com and target.com, both written in React, have all their speed metrics green, except for InteractionToNextPaint. This metric, introduced by Google, measures how fast clicks or keyboard inputs are on the page. In almost every React app, this metric is yellow or red, indicating a bad user experience. As this metric becomes a core vital in March 2024, your boss and marketing team will also become aware of its impact.

I start this talk with bad news. This is the PageSpeed Insights report for newyorktimes.com, written in React. It has all its speed metrics green, except for InteractionToNextPaint.

This is the PageSpeed Insights report for target.com, also written in React. It also has its speed metrics green, except for InteractionToNextPaint.

This is the Notion website. It also has all its speed metrics green, except for InteractionToNextPaint. This metric, InteractionToNextPaint, is a new performance metric introduced by Google. It measures how fast clicks or keyboard inputs are on the page. In almost every React app I've seen so far, this metric is yellow or red. Which means bad user experience, and which also means, as this metric becomes a core vital in March 2024, that also means that just in a few months your boss and your marketing team will also become suddenly aware that this metric is yellow or red.

2. Understanding the Impact of Slow Interactions

Short description:

The core idea behind this new metric is that it tells you how slow your app is. It calculates the slowest click or keypress on the page and sends it to Google servers. The INP value is computed by Google based on the slowest interactions from multiple users. In practice, a slow filter action in a note-taking app can make the app unresponsive. The interaction to an expanded metric is affected by slow interactions. By using the web vitals extension and checking the console, you can see the impact of slow interactions on the INP value.

Now, who here has worked with this metric before? Has anyone tried debugging or optimizing it? Actually, I can't see anything from here because of the lights. Well, all right, let's take a really quick dive into a theory.

So, the core idea behind this new metric is that it tells you how slow your app is. And when you see an interaction to next point of, for example, 393 milliseconds, here's how it's calculated. First, when you open any app or website on your Chrome, Chrome measures every click or keypress that you do on the page and finds the slowest one of them. Then, Chrome takes that slowest value and sends it to Google servers saying, hey, for this session the INP value was, for example, 500 milliseconds, which means the slowest click or keypress on the page was 500 milliseconds. And then, as more users visit the page and do the clicks and send their INP values, Google does the statistics magic and computes the overall INP for all the visits. So, that's what INP is. End of theory.

Let's see how it looks in practice. So, here is a very basic note-taking app. You could open a note, you could type into a note, it supports markdown, you could create a new note and you could also filter notes. And the filter not action, it's pretty slow. So, here in this corner, you could see this spinning bar, which is a spinner, which shows when the app is responsive. So, when the spinner spins, that means the app is responsive. When the spinner freezes, that means the app is also frozen. And if I try to type into this filter input, you could see that the moment I type, the spinner freezes for half a second or a second. This means typing into the filter is very unresponsive, I can feel that, and the page holds freezes for that period of time. So, that is about user experience. And this also worsens the interaction to an expanded metric.

Now, there's a very easy way, there's a very simple way to see how exactly the interaction to an expanded metric is affected by this. To see this, I'm going to go to the Chrome web store, I'm going to find the web vitals extension, I'm going to install it into Chrome. I'm going to open its options, enable console login, and then open the console on my page. And now, if I reload the page, and if I look into the console, I would see every core vital, every performance metric of the page of the app logged into the console. And if I try to interact with the app, like, for example, selecting some text, right, or just clicking some random places on the page or opening notes, I would see how long any interaction on the page I took. I mean, took. And if I try typing into the filter input, I would see that typing into the filter input is very, very slow. The interaction takes 500, 600 milliseconds and that results in a red INP. And you can also see how the more I interact with the page and the worse the interaction time gets, the higher the INP value also gets. Like INP is just the slowest interaction that's happened on the page, right? So you could see that every time I make an interaction that gets even slower than it was before, the NP value also goes up.

3. Understanding the Impact of Slow React Render

Short description:

My app is slow due to an expensive React render. This re-rendering process causes the input to be slow and leads to a poor user experience. To address this, React 18 introduces concurrent features, making updates non-urgent and allowing for prioritization of updates.

So, this is how INP is calculated. All right. Now, my app is slow, and INP is clearly showing that, right? And I could feel it, of course, on my own. Now, like IRB and like Target websites earlier, my app is also built with React. And if I were to debug this performance issue, I would see that this issue is caused by an expensive React render.

What's happening in the app basically looks as follows. So I type in the filter input. That filter input calls the setfilter function. That, in turn, changes the state in a bunch of components, and that causes React to render all these components one by one until React is done. And this is what makes my input slow. This re-rendering is a stop the world operation. Nothing could happen until the render is done. This is just how React works, right? When I type it on the keyboard, the page won't update until React has finished processing all the components. And if it takes two seconds to process all the components, then the page won't update until two seconds later. This is the classic slow React render, and this is what makes interaction to an explained bit.

Now, we have a performance problem, right? I type in the filter, and the app freezes. And that's a terrible user experience, and that also makes interaction to an explained bit. Now, normally if I were a developer on this app, I might try multiple things to fix this. I might try writing stuff with React Memo, optimizing the components, maybe virtualizing the list of nodes. Ken is actually going to talk about this later. I could try debouncing or throttling some stuff. And these are all great solutions, and you can even combine them. But here's the cool bit. What React 18 does is it introduces another solution to the mix, which is officially called concurrent features, and which I call making updates non-argent. What does it mean? So with React 17 and below, every update that happens in the app is considered argent. If you click a button, React has to handle the update immediately. If you type into the filter input, React has to render the list of nodes that we have in the app immediately. With React 18, however, your updates can now have a priority. Every update you make in the app is still by default argent. But what React now also supports is non-argent updates.

4. Optimizing React Rendering

Short description:

And non-argent updates, almost magically, don't block the page, no matter how long they take. React-TT allows splitting a single piece of state into two bits and connecting them to different components. By rendering non-urgent updates, React can prioritize the filtering rendering that users care about, while the other parts can wait.

And non-argent updates, almost magically, don't block the page, no matter how long they take. Let's see how this works.

So, oops, it went in the wrong direction. Here is the code for my app. This is the node list component, which is responsible for this sidebar that I have on the left. And it has two big things in it. It has the filter input component, which is this component. It has the list of nodes, which is this list of nodes, this huge list of all 1,500 nodes that I have in the app. And it has the filter state, which controls both the filter inputs and the list of nodes.

And so now, in this app, every time I type into the filter input, the filter state updates, and that state update is considered urgent. So React has to take that filter update and it has to render all the components in one go. I type, and it's slow. Right? So now, with React-TT, with React concurrency, what I can do is I could take this state update and I could take React that, hey, some parts of this state update are non-urgent. And here's how I'm going to do this.

So the first thing that I'm going to do is I'm going to take this single piece of state and split it into two bits. So I'm going to call the first filter input. And the second one filter value. Second, I'm going to take these two separate bits of state and I'm going to make them control different parts of the UI. So the filter input is going to control my filter input, obviously. And the filter value is going to control my list of nodes. And now I also need to update both of these states when I type into the filter input and that changes. So I'm just going to do this. I'm going to receive the value and I'm going to call set filter input, set filter value. Thanks, Copilot.

All right, so I took one bit of state and I split it into two bits of states and I connected these two bits of state to two separate components. So far this does not do anything, it just makes the app worse. Instead of one piece of state I have two pieces of state but the app is still slow, you can see I'm typing, it's terrible and it basically doesn't do anything else. But this is where the third, the key, bit of the puzzle comes.

Now that I have two bits of state that updates independently I could take the second bit of state that's responsible for the whole Nots list and I could tell React, hey React, when you make this state update, when you make a render that's triggered because the state changed, could you render it non-urgently? Because I as a user I don't really care if the Nots render right away, right? I care that the filtering that I'm typing into rerenders right away, I want to type and I want to see the letter that I typed in the right way. But the Nots, they could wait, they could wait half a second, they could wait a second, that would be just right.

5. Optimizing React Rendering with StartTransition

Short description:

To make the SetFilterValue state update non-urgent, import UseTransition from React, call the UseTransition hook with IsTransitioning and StartTransition values, and wrap the SetFilterValue call with StartTransition. This change improves user experience by preventing lag and freezing during interactions. It gives control back to the browser, allowing React to render the app and return control after every frame. React's queue of updates prioritizes non-urgent components.

That would work just fine. So I'm going to tell React that my SetFilterValue state update is non-urgent. And to do this, here's what I'm going to do. So first I'm going to import UseTransition from React. Second, I'm going to call the UseTransition hook, receiving two values. IsTransitioning and StartTransition. And third, I'm going to take my SetFilterValue call and I'm going to wrap it with StartTransition. That's it.

And so now, look at this spinner. I've done just a single change. I took my SetFilterValue and I've wrapped it with StartTransition. And before, without StartTransition, if you look at the spinner, you could see I'm typing and it lags, right? I'm typing and it's slow, it's annoying, it's bad user experience. It also makes the interactions really, really bad.

Now, if I wrap my SetFilterValue with StartTransition, what's going to happen is I'm going to type it in my filter input and nothing is going to freeze. So you could see in the right pane all the interactions are getting locked. They are green. And as I'm typing into my filter, the spinner just keeps spinning. Nothing is freezing. The app is completely responsive. I could type as much as I want and it's absolutely fast. The button is literally gone. This is almost magic. All right.

Now, could anyone guess how this works? This is a question to the room. Magic was the right answer, yes. So, no, the way this actually works is giving back control to the browser. React starts rendering the app and then gives the control back to the browser after every frame. Here's how this works from the React perspective. So, React has a queue of updates. In our case, this queue of updates has components that don't need to be updated urgently.

6. React 18 Rendering Process

Short description:

React 18 introduced two critical changes. First, it added a check called should yield to hosts, which determines when to give control back to the browser. Second, it schedules the next chunk of JavaScript activity using set-timeout zero. With React 18, state updates are categorized as argent or non-argent. Argent updates are rendered in a blocking manner, while non-argent updates are rendered in a non-blocking way, allowing control to be returned to the browser every five milliseconds.

It's the nodes list and a bunch of node buttons. So, React has a queue of updates. And React also has a function called perform work until deadline. This function basically takes the queue of updates and renders them one by one. Now, in React 17, this was pretty much it. You would start processing the queue, and you'd keep processing the queue until you're done. All this time, the page would be blocked. That was the Argent render.

Now, React 18 added two critical changes. First, in the while loop, it added a check called should yield to hosts, which tells React whether it should give the control back to the browser. And second, after the loop, React now checks whether there are still any pending unprocessed updates and schedules another perform work until deadline function to be executed in the next frame. So, take a queue, process it, return the control back to the browser if should yield to hosts tells you that you should return the control back to the browser, and then schedule more work if you return the control back to the browser early.

Now, should yield to hosts, the function that decides when React should give the control back to the browser is basically one-liner. It simply returns true if the current render has been taken more than 5 milliseconds. Now, schedule perform work until deadline function, the function that schedules the next chunk of JavaScript activity, the next chunk of processing the update queue, it's also pretty simple. It just calls the set-timeout zero. Who said that? Yay. It just calls the set-timeout zero to schedule the next perform work until deadline call or set immediate or message channel if there are supported React users damaged. And that's basically how it is implemented.

If you remember the slide from the past, this is how React 17 behaved when you tried the filtering input. You typed in the field. It changed the state in all of the components and then React had to process all of the components one by one. Freezing the page the whole time. Now, with React 18, this changes. When I tried typing into the filter field, React calls set-filter input and then calls set-filter value. This also causes the state to update in a bunch of components. But now, some of these state updates are argent, whereas other ones are marked as non-argent. And so, what React now does is it renders the argent updates in the old blocking manner, keeping the page frozen. But then it starts rendering non-argent updates. The updates wrapped with start transition in a non-blocking way, giving the control back to the browser every five milliseconds.

7. Improved Interaction with Concurrent Rendering

Short description:

And because the browser gets the control back, it can repaint the page much sooner. The first interaction is going to be faster, because we aren't blocked by all the non-argent components. And subsequent interactions are going to be faster. In Rec 17, the button would not react until the render is complete, but with concurrent rendering, the browser gets the control back every five milliseconds. So, it will dispatch the on-click handler right away, and then repaint the screen also right away. This would make the interaction process much faster and improve the interaction to Next Paint.

And because the browser gets the control back, it can repaint the page much sooner. It could handle all the interactions much sooner. The first interaction is going to be faster, because we aren't blocked by all the non-argent components. And subsequent interactions are going to be faster. Like, let's say the user tries to click something on the page, while the previous render, the non-argent render, is still ongoing. So, there is something to the filter input, and right away click something on the page, right? Within the next ten milliseconds. In Rec 17, the button would not react until the render is complete, until the previous render is complete. Which can take half a second, a second, two seconds, but with concurrent rendering, the browser gets the control back every five milliseconds. So, it will dispatch the on-click handler right away, and then repaint the screen also right away. And this would make the interaction process much faster, and this would also make your interaction to Nxt Paint much better. This is Rec 17's concurrent rendering, and this is how to browse interaction to Nxt Paint.

QnA

Concurrent React Features for Hydration

Short description:

React18 allows concurrent hydration by using suspense. Splitting the page into sections and wrapping each section with suspense enables non-blocking hydration. Wrapping the entire page with suspense can cause forced argent hydration, delaying the next paint. By wrapping separate page sections with suspense, only the clicked section hydrates argent, resulting in a shorter interaction to expand. These concurrent React features help improve INP.

Now, what we talked about so far was just one concurrent feature, useTransition. There's also another concurrent feature, which is less known, and it is suspense during rect hydration. So, if you're not familiar with rect hydration, the process of rect hydration is basically a process when you server render a site, then on the client hydrate that site, rendering every rect component again, attaching event listeners to the already existing DOM, and then you get the live set.

Now, hydration in my experience is typically the most expensive JavaScript operation that rect app could have, simply because rect has to render every single component that exists on the page, like, for example, here's delivery spending 1.55 seconds hydrating the site with 4x CPU throttling, or here's Notion spending 1.8 seconds, or here's Walmart spending 1.1 seconds, and I don't mean to dunk on this website or these teams. This is a standard situation. Every React site has this. This is just how rect hydration works. And what this means for interaction to NextPaint is, if you click the page somewhere during the hydration, then the browser won't process that click and won't repaint that screen until hydration is done because the browser is just blocked running the hydration, and that could happen. The hydration could end half a second or second later. So that results in a terrible time of interaction to NextPaint, but what React18 now allows you to take your site and hydrate it concurrently. In the same way that use transition works for interactions, suspense works for hydration. To do this, you need to take your page, like this notion landing page, for example, split that page into sections, like a header, a hero block, more sections, some further down, and wrap each of the sections with suspense, which would basically make the cut like this. And so what would happen now would be basically the following. You would call hydrate root. Rect will start rendering components one by one until it at some point stumbles upon the suspense boundary, which marks the non-blocking hydration, and when rect stumbles upon this boundary, it wouldn't proceed past that boundary just yet. It would keep rendering the remaining argent components until it's done, and then finally will render the non-argent ones given the control back to the browser every five milliseconds. So, if you wrap every page section with start-transition, what would happen is every page section would be hydrated non-concurrently given the control, sorry, concurrently given the control back to the browser every five milliseconds. Just like we use transition. Now you might ask, okay, if this is so good, if this makes the page hydrate non-blockingly, why do I need to bother with sections? Why don't I just wrap the whole page with suspense? And the answer is it's actually, it would actually flop your INP. Why? This has to do with another suspense behavior from React18. It doesn't really have a name, but I call it forced argent hydration. The challenge behind it is the moment you click some suspense button, React switches it back to argent hydration, so if you wrap the whole page with suspense, it will hydrate like this, 5 milliseconds at a time, but if you click it right when it's hydrating, React will switch to the argent hydration for the full page, which means the next paint won't happen until the whole page is hydrated, whereas if you wrap only separate page sections with suspense, which will give you a rendering that looks like this, and then click some suspense boundary, then only that suspense boundary will hydrate argent, which will take much less time and will make the first render after the click happen much earlier and will make your interaction to expand much shorter. So this is why you don't want to wrap the whole page with suspense. All right, so this is the two big concurrent React features. This is how they work and this is how they help with INP. Take them, take your INP and go make your INP green. Thank you.

Thank you for the questions. The first one says, is there any reason not to wrap most state updates in start transition? That's actually a great question. Hold on, let me think.

React State Updates and Suspense Boundaries

Short description:

I don't know. So, I think there are, I mean, there are some, there's definitely an answer to this. Sorry, I can't think of it. Well, I'm going to give Ivan homework. You're going to send us a Tweet about it later on so that they can find the answer for you. The scenario where used transition or used deferred value is helpful is when you're wrapping the state or reducer updates with them. You can also wrap the initial hydration or render with start transition. The cool thing about start transition is that it can wrap updates at any level of nested functions, even if it's a redux state update or another function that updates the state. The question of how granular suspense boundaries should be is important, as you may not want to wrap the entire page with suspense.

I don't know. So, I think there are, I mean, there are some, there's definitely an answer to this. Sorry, I can't think of it. Well, I'm going to give Ivan homework. You're going to send us a Tweet about it later on so that they can find the answer for you. Perfect. Find Ivan on Twitter slash X for response to that.

The next one we have is, what scenario than set state is used transition or used deferred value helpful? Could you say that again? Sorry. Yes. So, what scenario either than set state is used transition or used deferred value helpful? Oh yeah. I see. So, I mean, there are two ways, there are only two ways to update the state in your React app. It's used state or used reducer, right? So, at the basic level it's useful when you're wrapping either of these with used transition or used deferred value. You could sometimes also wrap the initial hydration or the initial render with start transition which you would in that case import straight from React and that would make the initial render or the initial hydration also concurrent. But in general, so in my example, I took used transition and I wrapped directly the set state call with the used transition, right? But that doesn't have to be the case. Sorry, I'm... No, you're okay. Yeah, I still haven't had my lunch. Oh, hungry! Well, let's give him a round of applause for doing this hungry. I would not be able to do that. But I want to finish answering. Okay, let's go ahead and finish. Thank you, that was helpful. Anyway, so the cool thing behind start transition is that it doesn't have to wrap the used state or set state at the basic level. Like, it could be it could be behind 10 levels of nested functions, right? If it's some redux state update or some other function that updates your state by proxy, you could still wrap it with start transition. It would still do the magic. Amazing, thank you. Let's see if we can take one short one. Okay, how granular should suspense boundaries be? Yeah, oh, this is a great question. So if you watch this presentation, you might wonder, okay, so I don't want to wrap the whole page with suspense.

Optimizing with Suspense

Short description:

Why not wrap every component with suspense? The React team says you can, but be cautious. Suspense has additional functions besides improving hydration, such as suspending data loading or lazy components. Excessive use of suspense can accidentally make unintended parts of the page suspenseful. The recommended approach is to wrap every page section for optimal efficiency.

And I explained why, right. But why don't we go in the opposite direction? Why don't we wrap every component with suspense? And I actually asked the React team this question and they were like, yeah, you could do that. The only reason you might not want to do that, that suspense actually has more functions. So apart from making the hydration better, it also suspends if you have some data loading or lazy components. And if you put too many suspenses around, you could accidentally make some parts of the page suspense when you don't want them. So the heuristic that I like is wrap every page section and that works well.

Optimize and be efficient.

Yes. Thank you so much, Ivan. Thank you.

Check out more articles and videos

We constantly think of articles and videos that might spark Git people interest / skill us up or help building a stellar career

React Advanced Conference 2022React Advanced Conference 2022
25 min
A Guide to React Rendering Behavior
React is a library for "rendering" UI from components, but many users find themselves confused about how React rendering actually works. What do terms like "rendering", "reconciliation", "Fibers", and "committing" actually mean? When do renders happen? How does Context affect rendering, and how do libraries like Redux cause updates? In this talk, we'll clear up the confusion and provide a solid foundation for understanding when, why, and how React renders. We'll look at: - What "rendering" actually is - How React queues renders and the standard rendering behavior - How keys and component types are used in rendering - Techniques for optimizing render performance - How context usage affects rendering behavior| - How external libraries tie into React rendering
React Summit 2023React Summit 2023
32 min
Speeding Up Your React App With Less JavaScript
Too much JavaScript is getting you down? New frameworks promising no JavaScript look interesting, but you have an existing React application to maintain. What if Qwik React is your answer for faster applications startup and better user experience? Qwik React allows you to easily turn your React application into a collection of islands, which can be SSRed and delayed hydrated, and in some instances, hydration skipped altogether. And all of this in an incremental way without a rewrite.
React Summit 2023React Summit 2023
23 min
React Concurrency, Explained
React 18! Concurrent features! You might’ve already tried the new APIs like useTransition, or you might’ve just heard of them. But do you know how React 18 achieves the performance wins it brings with itself? In this talk, let’s peek under the hood of React 18’s performance features: - How React 18 lowers the time your page stays frozen (aka TBT) - What exactly happens in the main thread when you run useTransition() - What’s the catch with the improvements (there’s no free cake!), and why Vue.js and Preact straight refused to ship anything similar
JSNation 2022JSNation 2022
21 min
The Future of Performance Tooling
Our understanding of performance & user-experience has heavily evolved over the years. Web Developer Tooling needs to similarly evolve to make sure it is user-centric, actionable and contextual where modern experiences are concerned. In this talk, Addy will walk you through Chrome and others have been thinking about this problem and what updates they've been making to performance tools to lower the friction for building great experiences on the web.
JSNation 2023JSNation 2023
26 min
When Optimizations Backfire
Ever loaded a font from the Google Fonts CDN? Or added the loading=lazy attribute onto an image? These optimizations are recommended all over the web – but, sometimes, they make your app not faster but slower.
In this talk, Ivan will show when some common performance optimizations backfire – and what we need to do to avoid that.

Workshops on related topic

React Summit 2023React Summit 2023
170 min
React Performance Debugging Masterclass
Featured WorkshopFree
Ivan’s first attempts at performance debugging were chaotic. He would see a slow interaction, try a random optimization, see that it didn't help, and keep trying other optimizations until he found the right one (or gave up).
Back then, Ivan didn’t know how to use performance devtools well. He would do a recording in Chrome DevTools or React Profiler, poke around it, try clicking random things, and then close it in frustration a few minutes later. Now, Ivan knows exactly where and what to look for. And in this workshop, Ivan will teach you that too.
Here’s how this is going to work. We’ll take a slow app → debug it (using tools like Chrome DevTools, React Profiler, and why-did-you-render) → pinpoint the bottleneck → and then repeat, several times more. We won’t talk about the solutions (in 90% of the cases, it’s just the ol’ regular useMemo() or memo()). But we’ll talk about everything that comes before – and learn how to analyze any React performance problem, step by step.
(Note: This workshop is best suited for engineers who are already familiar with how useMemo() and memo() work – but want to get better at using the performance tools around React. Also, we’ll be covering interaction performance, not load speed, so you won’t hear a word about Lighthouse 🤐)
JSNation 2023JSNation 2023
170 min
Building WebApps That Light Up the Internet with QwikCity
Featured WorkshopFree
Building instant-on web applications at scale have been elusive. Real-world sites need tracking, analytics, and complex user interfaces and interactions. We always start with the best intentions but end up with a less-than-ideal site.
QwikCity is a new meta-framework that allows you to build large-scale applications with constant startup-up performance. We will look at how to build a QwikCity application and what makes it unique. The workshop will show you how to set up a QwikCitp project. How routing works with layout. The demo application will fetch data and present it to the user in an editable form. And finally, how one can use authentication. All of the basic parts for any large-scale applications.
Along the way, we will also look at what makes Qwik unique, and how resumability enables constant startup performance no matter the application complexity.
React Day Berlin 2022React Day Berlin 2022
53 min
Next.js 13: Data Fetching Strategies
WorkshopFree
- Introduction- Prerequisites for the workshop- Fetching strategies: fundamentals- Fetching strategies – hands-on: fetch API, cache (static VS dynamic), revalidate, suspense (parallel data fetching)- Test your build and serve it on Vercel- Future: Server components VS Client components- Workshop easter egg (unrelated to the topic, calling out accessibility)- Wrapping up
React Advanced Conference 2023React Advanced Conference 2023
148 min
React Performance Debugging
Workshop
Ivan’s first attempts at performance debugging were chaotic. He would see a slow interaction, try a random optimization, see that it didn't help, and keep trying other optimizations until he found the right one (or gave up).
Back then, Ivan didn’t know how to use performance devtools well. He would do a recording in Chrome DevTools or React Profiler, poke around it, try clicking random things, and then close it in frustration a few minutes later. Now, Ivan knows exactly where and what to look for. And in this workshop, Ivan will teach you that too.
Here’s how this is going to work. We’ll take a slow app → debug it (using tools like Chrome DevTools, React Profiler, and why-did-you-render) → pinpoint the bottleneck → and then repeat, several times more. We won’t talk about the solutions (in 90% of the cases, it’s just the ol’ regular useMemo() or memo()). But we’ll talk about everything that comes before – and learn how to analyze any React performance problem, step by step.
(Note: This workshop is best suited for engineers who are already familiar with how useMemo() and memo() work – but want to get better at using the performance tools around React. Also, we’ll be covering interaction performance, not load speed, so you won’t hear a word about Lighthouse 🤐)
Vue.js London 2023Vue.js London 2023
49 min
Maximize App Performance by Optimizing Web Fonts
WorkshopFree
You've just landed on a web page and you try to click a certain element, but just before you do, an ad loads on top of it and you end up clicking that thing instead.
That…that’s a layout shift. Everyone, developers and users alike, know that layout shifts are bad. And the later they happen, the more disruptive they are to users. In this workshop we're going to look into how web fonts cause layout shifts and explore a few strategies of loading web fonts without causing big layout shifts.
Table of Contents:What’s CLS and how it’s calculated?How fonts can cause CLS?Font loading strategies for minimizing CLSRecap and conclusion
React Summit 2022React Summit 2022
50 min
High-performance Next.js
Workshop
Next.js is a compelling framework that makes many tasks effortless by providing many out-of-the-box solutions. But as soon as our app needs to scale, it is essential to maintain high performance without compromising maintenance and server costs. In this workshop, we will see how to analyze Next.js performances, resources usage, how to scale it, and how to make the right decisions while writing the application architecture.