Getting Started with Suspense and Concurrent Rendering in React

Rate this content
Bookmark

React keeps on evolving and making hard things easier for the average developer.


One case, where React was not particularly hard but very repetitive, is working with AJAX request. There is always the trinity of loading, success and possible error states that had to be handled each time. But no more as the `<Suspense />` component makes life much easier.


Another case is performance of larger and complex applications. Usually React is fast enough but with a large application rendering components can conflict with user interactions. Concurrent rendering will, mostly automatically, take care of this.


You will learn all about using <Suspense />, showing loading indicators and handling errors. You will see how easy it is to get started with concurrent rendering. You will make suspense even more capable combining it with concurrent rendering, the `useTransition()` hook and the <SuspenseList /> component.

125 min
15 Jul, 2021

Video Summary and Transcription

This workshop explores suspense, lazy loading, bundle splitting, and data resources in React. It covers UI approaches to make applications appear faster and concurrent modes for more responsive applications. React.lazy is used to optimize loading and bundle size, while React Suspense is used to suspend rendering until components are loaded. Data resources can be created using the same principle as React.lazy. The workshop also discusses error handling, parallel suspense, and fetching data before rendering. Concurrent modes offer a solution to rendering delays and event handling in single-threaded JavaScript environments.

1. Introduction to Workshop

Short description:

Welcome to this workshop on getting started with suspense and concurrent rendering and React. I'm Maurice de Bayer, a freelance developer and instructor. The goal of this workshop is to explore suspense, lazy loading, bundle splitting, and data resources. We'll also cover UI approaches to make applications appear faster and concurrent modes for more responsive applications. It's important to type the code instead of copying it for better learning. Prerequisites include Node, NPM, and cloning the repository.

So, let's get started, and if anyone else joins, they're not going to miss a lot because we're just starting with the intro. So welcome, everyone, welcome to this workshop on getting started with suspense and concurrent rendering and React. So who am I? I'm the guy who tries to forward the slides with the wrong focus. So that doesn't work. But now it does. So I'm Maurice de Bayer, also known as the Problem Solver. I'm a freelance developer and instructor, which kind of works nicely together. I teach what I do and I do what I teach. So it keeps me sharp.

Twitter handle is MauriceDB. So if you want to follow me. The slides are on several places, they're actually on the GitHub repo, which I'll share in a minute. They're already on SlideShare. They're on my website as well. It's kind of useful to keep them handy. There are lots of links in here to snippets of code or divs. You can follow along a bit easier than just remembering what I did and then trying to do the same. I do a lot of stuff, teach, develop, but I also publish the React Newsletter, which is a weekly newsletter, comes out every Wednesday afternoon, and has a bunch of articles about what's interesting about React and, well, React in a loose term, so everything related to React as well.

So about this workshop, the goal. We've basically got three main subjects. We're going to take a look at what we can do today. Use suspense, use lazy loading, bundle splitting, use data resources to load data. Then we're going to take a look at some UI approaches to make the application appear to be faster for the end user. It's actually not going to be faster because exactly the same happens, but we can make things happen in a different order so things actually appear faster, which is pretty nice. And suspense isn't a requirement for that, but it does make it a lot easier. And then the last bit is about concurrent modes, where we're going to do concurrent rendering. That's pretty much future stuff that's not possible with the current version of React. So we'll be using the experimental version of React to do that. In fact, we'll be using that all of the time, but you won't really be able to tell the difference until we get to that part. And with that, we'll be able to make applications more responsive. And we'll be able to orchestrate suspense boundaries using suspense list and transitions and things like that. So pretty nice. But keep in mind that's all very much in the future that's not available with the current released version of React. So we're kind of going from available use today to you can use this in the future.

Now a little tip. I'm providing you with all of the code you need. And you could just simply copy the code from the browser into Visual Studio code or whatever editor you're using. But in the end, you'll come away with an impression of what you did. And you've really honed your copy and paste skills. Copy and paste is an important skill. But if you want to learn something new, it's not the best way to learn it. So by actually typing it in, doing it, making mistakes, fixing those mistakes, you'll learn a lot better and you'll remember a lot better. So I would highly recommend not to copy too much.

So some prerequisites. I'm assuming everyone's good to go there. But just in case, you need to have Node installed because the React application we're going to use is built with create React app. So it's basically a nodes develop time stack. We need NPM to install packages, etc. Well, NPM ships with nodes by default, at least almost everywhere. Some Linux distros don't but I'm assuming everyone has that setup because this is for experienced React developers. So I'm kind of expecting all of that to be done. This is my setup at the moment. I've got nodes 12.18.3 and NPM 6.14.8. You don't need to have exactly the same versions like if you're on some version 12 of node, that's perfectly fine. Some version 10 will actually be fine as well. And the same with NPM, it doesn't need to be exactly this version but anything relatively recent will do. If you're on node six or something like that, yeah, then things won't work. But then any react stuff won't work. So that's a standard stuff.

The other thing you'll need is the repository and let me grab the repository and drag that over. Here it is. So this is basically as you can see from the bottom here done with create react app, a standard application. There is a source folder inside the source folder, there is a custom components folder with a bunch of components. I'll be showing lots of details about those later, and we'll be making lots of changes in that. So you need to clone that, click on this button, copy whatever is in here, use HTTPS or SSH, that doesn't really matter. So copy this and do a Gits clone somewhere on your disk so you get a copy of all of this. So the URL I'm going to show it again in the slides, but just in case you want to grab the entire community. So you can also scan this barcode or if you've already downloaded the slides so you can just click on it. It's actually a link and it will take you to repository as well, or if you scan the QR code, it will get you there as well. So once you've cloned that, open up a command window terminal window in that folder where it was clones.

2. Cloning Repository and Starting Application

Short description:

In this part, you'll learn how to clone the repository, install the dependencies, and start the application. You'll also explore the slides and links provided in the repository. Additionally, the breakout room feature of Zoom will be used to split participants into small groups for collaborative work. The first topic to be covered is using react.lazy and bundle splitting.

So in this case, for me, that's repos react suspense 2020 and execute an NPM CI or an NPM install there. Either will work, NPM CI slightly faster. That's why I prefer but NPM install will do exactly the same thing and it will install the dependencies shouldn't take very long. Took 8.7 seconds on my machine, but I've got a pretty fast machine. So pretty good. There.

Now, you'll see lots of slides like this as well during the workshop. There's code in there now. These are images. So it's kind of hard to copy the code from there. But they're also links. If you click on this, you get to the git diff, which is actually the cause of that change. So you see here, for instance, we had some import statements and they were commented out in this diff and they were replaced by react.lazy, which is actually pretty much the first change we're gonna do. That's why it's useful to have these around. You can click on the image, get to the diff.

Now, the slides are actually in here. They are in the repository. Only the not-so-nice thing with GitHub is that all of these are images. So I can scroll down to this same image and I can click on it, but nothing happens. Basically, what GitHub does is it renders an image for every page, which makes it perfectly but not interactive anymore. So it's recommended not to go there, but take this link instead. And I need to go here to click on it. It's exactly the same PDFs, but now they're hosted on my website and you can scroll down to the same image. Where is it here? And now I can click on it, and it does actually work. It is properly. Just to make life easier, you can also download it and open it some other way, but just make sure not to download it from the Git repository on GitHub because then the links don't work.

Another thing you'll see quite a bit is this guy, Jean Luc Picard's with Make It So, which is basically your cue to do stuff. I'm going to use the breakout room features of Zoom, so I'm basically going to split you up into a bunch of different breakout rooms with three or four people, so small groups so you can work together, ask each other questions, etc. This is basically the cue that's going to happen. I will try to keep the breakout rooms exactly the same. I've had some issues in the past with Zoom where it would forget about where a specific breakout room was, so I had to manually put them in, and I wasn't always sure which room that was. As a result of that, you might switch rooms, but barring that, I'll keep the same rooms with the same group of people so you can get used to working together as well, helping each other. With that out of the way, and actually I did not want to go there, that's actually kind go to the breakout rooms now. Make sure that you've got a working setup. So start the application. If you go to the shell you can do npm start, after you've cloned it and did the npm install. It should start up and basically show you a pretty simple application. You should be able to click on Movies. Click on Users, you'll see some users, and you see a loading spinner, you click on the You'll see some details and actually this is an interesting thing to see. You actually see two spinners there and they resolve always in the order where the user's favorite movie shows up first and then the user details. Not very important right now, but that will actually come up several times. So that should be working for you. So that shouldn't take very long, but let's go to the breakout room for a few minutes and then everyone can come back to the main room. I'll close the breakout rooms and we'll continue with the first step where we're actually going to do anything. Now, if you get stuck for some reason, anywhere along the process. Check with each other, try to help each other. If you can't, you can ask for help for me and I'll join you in the breakout room to help you out there as well. So let's see, I need to decrease the number of rooms a bit. So I'm going to break it out into seven different rooms. So there will be three or four of you in the same room. So I'm going to open them and give you a few minutes to make sure that the repository is cloned, NPM install is done, and it starts up properly. So I'll see you in a few minutes. So most people are back, not everyone. That actually closed a bit sooner than I was expecting, sorry about that. But apparently the breakout room was set to auto close in two minutes, which was not what I wanted. But I can't change it once it's opened, which is unfortunately in Zoom. But I'll change that before we open it again. So let me change the options right away. I do not want them to close automatically. So next time that won't happen. So hopefully you've had some time to clone the repository and at least do the npm installs. So let's start running. And while that's running, let's actually go and do the first thing. So the first thing we're going to take a look at is using react.lazy and bundle splitting. In order to see what's going on. I've got this application running but I'm actually going to stop it. And let's first editor here. I'm going to go to the package json. And I've got this analyze script which I added. That's not there by default.

3. Optimizing Bundle Size with React.lazy

Short description:

To optimize the loading of React applications, we can use React.lazy to create lazy wrappers for components. These wrappers are only evaluated when the component renders, preventing unnecessary loading of code. By using React.lazy, we can load components on-demand based on the routes or user interactions, reducing the initial bundle size and improving performance. To implement React.lazy, we can comment out the components we want to lazy load and use the React.lazy function with the import statement. This creates a lazy wrapper for the component, which is only evaluated when needed. We can apply React.lazy to multiple components, ensuring that only the necessary code is loaded.

But I installed a tool called source map explorer. And that will basically tell me what kind of bundles are created and how they're wired up. So if I take this and I go back to the console and I do an NPM run analyze. It's going to create the build version of the application, which takes a bit of time and then it will start the analyzer on that.

Now that's relatively fast. So here at the top, you've got a little drop down, and that shows us the different chunks which are available. So if I zoom in a bit, you can see there is this runtime-main. It's pretty small 1.55 kilobyte. That's a bit of overhead. Runtime file required. Not very important. Then there is this, a 2. and then a hashCode.chunk.js. That contains most of the node modules. So react, react-dom, etc. And then in the middle, a little hard to read now, there is this main- and again some hashCodes-chunk.js. That actually contains our code. So I can open that main, and we can see in here that there is a user movie details, and there is a NavBar here, users, there's a ServiceWorker, app.js, etc. Basically the code from our applications.

If I go back to this, you see there is an index.ts, which renders an app.ts, and that renders a bunch of components. We kind of see all of these here. And then there was that to.hashCode.chunk.js. And in here you can see stuff like we've got React here, there is a scheduler, which is part of React, and whole bunch of NPM packages. Now for a small application like this, that's fine, no problem. But if your application becomes larger, where's my app? In this case they're not that many components, but with a larger application, you're gonna load up everything up-front when you first start the application, and the user might never even go to that page, or maybe he isn't even allowed to go to that page, maybe part of your application is an admin section, so only admin users can go there, and regular users won't even be able to access them, even if they wanted to. So it's kind of wasteful to load them. It's also true for lots of npm packages. They might be needed in one or two pages, but not your whole application.

Well, I work on quite a few React applications. They tend to get larger, and your whole bundle becomes larger and larger, and it's not uncommon to see React applications that load up five megabytes or more of code when they start, regardless of whether that's actually needed. Turns out that's really easy to fix. In here, I've got three components, movies, users, and user details. And one good way to think about these is, well, these are actually different routes. I've got users, movies, and the details. And that kind of shows up here. We're on users now. I can click on movies, we can see the movie details. We're only loading one of these at a time. Same if I go to user details. Different URL, we're only loading this. Even if I hit F5 from here, I can hit F5 and refresh it. I won't do it now because I'm not running the application, at least not in node at the moment. So I'll just get a timeout from the browser. But I don't need to load the components to render movies if I just go to this page, if I press F5.

So in order to not do that, pretty simple. I can just comment these out and we can say, we'll use React lazy. React.lazy takes a callback. In here we call import, a standard function which is available. And you say what we want to import. So the thing we were importing before. So we end up with a movies component. Except not quite. We don't end up with a movies component. We end up with a lazy wrapper for the movies component. So this React.lazy kind of creates in wrapper components which will only be evaluated when that component actually renders. So if it doesn't render it never borders to execute whatever is in here. So it never actually loads those components. We can do the same for users and user details. Let me include those. Users and user details. And let me go back and start the application again and it should start up just fine. We can still go to users or movies where I was to users here, user details. It's kind of looks like our application is exactly the same as it was before. It isn't, in fact, it's broken. Now I can do F5, of course, everything's running. And if I hit F5, we get this nice error dialogue. This is custom error and error I added. But it actually complains about React components suspending, etc. So we're not actually done here but if I load the application from the main entry point, localhost port 3000 without anything, I can go navigate around and everything seems to work. So what happened behind the scenes with the bundle? Well, let's run that analyze again.

4. Building and Bundling

Short description:

Creates another build to split the code into separate bundles. The main bundle now contains only a handful of components, while the rest are in other bundles. However, there is some duplication and missing dependencies. When running the application using npm start, it works fine until a page refresh. Serving the build version also leads to broken links. We need to add suspense elements to fix this.

Creates another build. Let's go back to the console for a moment. You can already see down here that it's built quite a bit more. Was it two.hash.junk of three or four or five? And we still have the main and the runtime. So combined, everything is still about the same size. But if I go to two.js, still got our code. Let's actually go to main first. So just a handful of components. I still have the other one open. So before I split, if I look there at main.js we see things like movies.tsx. Labeled textarea.tsx, et cetera. Over here all of that's gone. In fact, they'll be in one of these other bundles. Not sure which one. Not actually seeing what's in here. Let's see. Oh, here. There. So here's the user movie details, the user user details, et cetera. So these are the user details. In this one, there's the user card user. So that's the user page. We can see there are also some note modules in here, and there is other stuff being duplicated. So there is a bit of duplication going on. We can get around that, but by default, it will suck things into this bundle, which are needed for that bundle, which are not loaded up in the main bundle yet, because that's a lot smaller now. Now I mentioned that, and I demoed that when I run the application using npm start, it actually runs just fine, as long as you don't refresh. If I serve up to build version, so I'm using server, which is a small HTTP server and running the build folder. So whatever was deployed, I can go back to the browser and go to localhost ports 5000. And we see exactly the same application, but now as soon as I click on one of these links, it's broken. This is what the user would see. We need to add the suspense elements, we'll do that in a bit, but first we're going to do this.

5. Getting Started and Branches

Short description:

Before starting, let's address a few things. TypeScript is used in this workshop, but if you're not a fan, you can ignore it or use the 'any' type. There are multiple branches in the repository, but start with 'zerostart'. React lazy and bundle per route are covered. To avoid duplicated code, import specific files or bundles. React.lazy allows importing components asynchronously. Start with the 'zerostart' branch and follow the steps. If any issues arise, try other branches. Let's go to the breakout rooms and continue in five minutes. Please let me know if you encountered any problems.

Now, couple of things before you get started. First, you might have noticed the file extension, I'm using TypeScript here. I've got an aptel TSX and everything else, and there is some type information. Like there is some type information here. I've got app, which is of type react.fc, a functional component. I fully realized not everyone likes TypeScript. I'm a big TypeScript fan. I think it's really useful to have type checking and prevent a lot of potential errors, but some people don't like it. If you're not a big TypeScript fan, just ignore it. You can copy exact types you need. Quite often you can just leave them out. In this case, if I would leave that type information out, it would be fine. And then other cases, if something is complaining, just put in colon any. TypeScript has this any type, and if you put in the any type, it basically says, okay, we'll forget about type checking here. We'll just trust you. So if you don't like TypeScript, that any is your escape hatch. The other thing you need to be aware of is branches. I've got a whole bunch of branches here. Now you just cloned repo, so you're gonna be on the master branch. The master branch is basically the end result where everything's done. There are a bunch of branches here, and the one I'm actually using, it doesn't show up, that's this one, zerostart. So that's the one you want to start with when you get started. Now all the steps we're gonna do basically build on top of each other. So if you do this step starting with the zerostart branch, then you can do the next step on top of that, et cetera. You can kind of keep on going. But if for some reason it doesn't work for you, you can pick any of the other branches. So one lazy, I'm not gonna switch now because I've got changes, but if you select that, that's the first step completed. We've got lazy. Two means suspense. So suppose we're gonna start doing parallel suspenses. Well, that's completed with branch five. So branch four has the previous step completed. So that's how you can get around not finishing or not being able to complete any given task. But ideally you should just be able to start with the zero star branch and then keep on going. So back to the slides, kind of mentioned all of this already. React lazy is really useful. It's really simple to use. We've done almost everything you need to do. We'll do one more bit in order to get it to work properly. But that's a really small step as well. If you start with this bundling the way I did, using this bundle as a route, bundle per route is a really good way to start because typically that's a URL, an entry point to your application. But as I mentioned, shared code could end up in multiple bundles. The way around that we are not actually gonna do that, but just gonna show you. Like the rest is loading indicator here, which is used in quite a few pages. Well, if you want that in your main bundle, the best way is to go here and just import this, except this goes to components now, loading. Now this would almost work, this would import that bundle, but then tree shaking would actually come in with webpack and it would say, well, you imported loading from that's loading folder or file, but we're not actually using it. So it would bundle it and then tree shake it out again. So what you wanna do is remove that, just say import a specific file or bundle or whatever MPM package. And now that whole item, in this case, that these X file is included and it will be in your main bundle and will not be duplicated in all your other bundles. So a little tip to get around it. Also, we're using import here, which basically gives you a promise to something you can import. React.Lazy is specific for components, so you can only import React components with it, but you can import anything you want asynchronously with automatic bundles plotting. Webpack sees the imports function being called and knows that whatever is after that, past is a parameter, should be a different bundle. So you can actually split out utilities you don't really need or maybe only occasionally need, stuff like that. It's pretty generic and pretty easy to use. But like I said, we're not gonna do that. Just gonna do this bit. So again, as a reminder, start with the zero start branch. If you click on this image, you'll get the exact diff, pretty small in this case, of what the change is that is required. So, there is Jean-Luc Picard. So, let's go back out into the breakout rooms and do this. I'll add a bit of time, just in case the NPM install didn't quite work out, and then just finish that if required, and then do these steps. And I'll see you all in say five minutes. So, see you in five. Okay. So, everyone's back. Did everyone succeed in getting the application up and running and making the first change? If not, please let me know. So, I can keep that in mind for the next steps. So, just either speak up or leave a message in the Discord channel. And I see a couple of messages in the Zoom chat as well.

6. Understanding React Suspense and React.lazy

Short description:

React Suspense is a special component that allows suspending the rendering of other components until they are loaded. It works by throwing promises and catching them to suspend rendering. When the promises are resolved, the component is re-rendered. React.lazy is used to asynchronously load and render components. Suspense does not need to be the direct parent of the component to be suspended. A main suspense boundary can be added at a high level in the application to catch any component suspensions. A fallback prop is required for suspense, which can be a loading indicator. However, in the development version, the loading indicator may not be visible.

That it's working. Okay. That's good. So, we added React Lazy and that worked. It was actually pretty simple, so it shouldn't be a big surprise that that worked. But, we also saw that it didn't completely work. We actually needed something else. And the error message already said it. We needed something called suspense.

So, what's this suspense thing? Well, the suspense thing, or component as I should say. Because it's really just another component. It's kind of a special component from React itself. And it's special because it lets you suspend rendering of other components. And how does it work? Well, basically if it detects that another component wants to suspend rendering. Then it's going to suspend its complete sub tree and basically allow that component to finish whatever it does.

Now in the case of React Lazy, suspending happens when you want to render a component but that component hasn't actually been loaded yet. So, the bundle, the chunk of codes required to render that isn't actually in memory in the browser and available yet. So an AJAX request happens, the bundle is loaded and only when it's loaded can the application resume. So, it becomes unsuspended. Now how does the suspend component actually know that? Well, there's this little trick with suspense. It uses a throw but in a kind of a weird way. Normally when you think about throwing, you think about try-catch and errors. So, you throw an error that something went wrong. Well, they're kind of doing that except they're not throwing errors, they're throwing promises, and they're catching a promise and they're kind of looking at it. Okay, I've got a promise. So, we'll suspend rendering. We're not going to see this as an error. We're not going to go to an error boundary or anything. We're just going to suspend rendering. And as soon as the promise is resolved, we're going to assume that whatever needs, needed to be done is done and we can re-render that component and it will render this time. Quite possibly, it will suspend again because it needs to load some data. And then we get into the whole cycle again, a promise is thrown, the promise resolves when the data is loaded and the component renders again. Now, we're not going to take a look at data yet. We'll be there quite quickly, but for now we're just going to take a look at the react.lazy part.

So, async is loading the component, executing the code and then rendering that component. Now, react-suspends is set up in such a way that it does not need to be the direct parent of whatever you want to suspend. So, in our case, we've got the application object which has react-router in there and we basically suspend routes the first time they're executed in order to load the components. And it's perfectly fine to add react-suspends right there. In fact, we will be doing that later. But what I typically do is somewhere really high up in my application, so like this example in the index.tsx where I actually do react-dom.render, I add main suspense boundary which will catch any component suspending inside. Is that the ideal place? Probably not but it means that any suspense object or anything that needs to suspend will be able to without crashing the application. And then later in I'll start adding multiple suspense components to trap those suspensions in a more logical place. And that's the next step we're going to do but first we're going to add this high level suspense. So I'm going to go to my index.tsx and basically inside this React strict mode which was added by create-react app itself, I'm going to add suspense here. So we can add suspense or do react.suspense. It would need to resolve but for some reason it doesn't want to so ah, it doesn't need to resolve it was already in there. So it complains there's an error there, which is one of the reasons I like TypeScript so much, it tells me right away that there was something missing. Well, the thing missing is a fallback prop. It needs a fallback prop. And that's an expression which is some kind of component, so I could just put a div in here, say loading, for instance. We can go back to the application. Do I still have it running? No, that's the built one, so do an npm start. So it starts and now, if I click on movies, it's actually really hard to see. I'll make it a bit slower in a sec, but we should briefly, at the tops, see loading. But to be honest, I can't even see it. So let me refresh this again. We'll go to the Network tab, and we'll And we'll fake our network to be slow 3G. So it takes a long time. I click movies. And I still didn't actually see that loading indicator, which is probably because I'm using the built, sorry, not build version, the development version. So let's build it again and do the same thing with the build version. The reason we're not seeing it is probably exactly the same reason why it doesn't throw an error immediately in the development version. So run this version. So I still had it opened right here. Go to local, to the homepage, click on movies. And now you could very briefly say, loading there. Let me do that with a slow network. So slow 3G. I click on movies. You see much clearer now loading.

7. Optimizing Loading and Suspense

Short description:

The component is loaded and rendered, with the required code being loaded. When navigating between pages, chunks are loaded only when needed. The nav bar disappears because the suspense boundary replaces the complete content of the suspense object. Nesting suspense objects allows for more control over what gets suspended. The app component contains components that get suspended, while other elements like the nav bar remain. Adding another suspense element around the switch ensures that only that part is suspended. Rebuilding and serving the application shows a nicer experience with the navbar staying visible during suspension.

Now the component was loaded and you actually see it being rendered. And if I go right to the top, you can see that this chunk was actually loaded. That's the code required for those movies and the movie cards inside of that, et cetera. Now, I'll clear this. I'll go back to the homepage. So nothing to load here. If I click on movies again, you can see there is a request for those top rated movies, but there was no request for the actual chunk again. So the first time a chunk is required, it's loaded. The second time when the component tries to run, which as well, the chunk of code I need is actually already loaded. So we're good to go. So if I clear this and click on users, I haven't visited the user's page yet. I should see another chunk appear. So again, we see loading here, kind of an indicator as well. And we can see that chunk being loaded because that's the first time we actually needed this chunk. Again, if I go back to movies, no chunks loaded, just movies. If I go back to users, no chunks, just users. If I would click on details, we'd see those, that chunk being loaded for the first time. Let's go back to the development environment and make this a little bit nicer because this kind of works, so it turns out I've got a nice loading indicator. So I can just put that in there and it will show a nice spinner. Except we're not going to see it. So let me do the same thing. Build it again and run the build version so we can see the spinner. So where is it? That's the surf command. So web server is running, local host port 5000. So this is the built version. Let's go to the home page, make sure nothing is loaded. So I refreshed it, slow network again. Clear this so we can see what's going on. Click on movies. Now we see a nice spinner. Then we see the nav bar come back in, which is the point where the component actually renders and it starts fetching its data. Now, why does the nav bar actually disappear? That's because in app.js we're saying, well, this component renders whatever route we're on, so it renders the movie components, but it's also the one that renders the nav bar. And if I click the movies, this was the component which would suspend. But back in Index, it basically says, well, this is the suspense boundary. So everything inside of it, so the error boundary and the whole application is suspended and instead of all of that, it's just gonna show that loading indicator. So it doesn't replace just a suspended component, it's gonna replace the complete content of the suspense object, which is one of the reasons you typically want to use multiple suspense objects. But we're not gonna do that yet, we'll do that after this step. So let's make it so add to suspense boundary in the index dot tsx and make sure that works. And in order to see it work, you'll have to create a build version and run the build version because in development version, the webpack actually pushes all the bundles straightaway to the client. And it's not actually that easy to see the asynchronous loading. So I'm gonna open up the breakout rooms again for five minutes and I'll see you in five. Let me know if you run into any problems. Remember, if the previous step worked fine you can just continue with the same code. If it didn't, you wanna switch to, where are my branches? You wanna take one Lazy as the start because that's the step we're doing right now. But if so far, everything worked fine, then you can just continue on the same branch. No need to switch. So see you in five minutes. Okay, sorry, and everyone's back. So let's go to do the next step. And as I already mentioned before, you can nest suspense objects or components, I should say. So you can exactly control what gets suspended. So you can basically add as many as you want, they can be in parallel, they can be nested. And whenever a component wants to suspend, for some reason React.lazy in this case, it's just gonna find the closest parent suspense and use that to suspend. So we can control that. In our case, we've got suspense here. But that means that whenever something suspends the whole application kind of disappears. You just get that spin or loading spin and then when whatever is done, the whole application comes back. And if we look at the app component, we can see, well, that happens somewhere in here because these are the components which basically gets suspended, some movie user or user details, but things like that nav bar, or maybe there is a footer there, or even more stuff that doesn't need to be removed when suspension happens and recreated when it resumes. So what I typically do is say, well, in this case, we want to do another suspense element here, wrap it around the switch. So just that part is suspended. We can add a fallback in here, just like before, add the loading component there. And now, if we rebuild the application and serve it again, but now when the application suspends because of one of those lazy components needs to load, it's actually just going to leave the nav bar there, it's gonna find the closest suspense and it will be a much nicer experience. So, let's go back to home. I just hit F5 to make sure that no extra components or bundles are loaded, just this bit. So, just like before, slow 3G, click on Movies. And now we get this loading indicator, but the navbar stays there. And more importantly, let me do this again and make sure it's unloaded by refreshing. The first time I did it before I did the suspense, then the navbar would go away, you would see a loading spinner, then the navbar would re-render, you would see the loading spinner again, but slightly lower. And only then would you see any components being loaded. Well, right now that isn't the case anymore.

8. Adding Suspense Component

Short description:

The component was loaded, the chunk for the component was loaded, the component was rendered and it decided that it needed some data. The user can't tell, they see exactly the same spinner in the same location, they can't tell, it's actually one spinner because of the component being loaded, a second spinner because of the data being loaded, visually not noticeable, so much nicer.

Navbar is there, you see loading, you still see loading in the same place, but in the network you could actually see that this top-rated movie Ajax Request was done. Well, that's the point where the component was actually, the chunk for the component was loaded, the component was rendered and it decided that it needed some data. But the user can't tell, they see exactly the same spinner in the same location, they can't tell, it's actually one spinner because of the component being loaded, a second spinner because of the data being loaded, visually not noticeable, so much nicer. So basically, like I said, you can end as many as you want. So in this case, I repped the switch component and we're actually going to add more suspense components for exactly the same reason later on. But for now, let's go ahead and add this suspense component and make sure you get the same behavior as I did. So I'm going to open up the breakout rooms again. This is a pretty small change and you should have the hang of it now. So I'm just going to open it for three minutes and after three minutes we're all going to come back and do the next step. So you can contain, at least if everything worked fine, you can keep working in the same branch. If you've run into problems, then you can always switch to a new branch to get started. Hopefully you can just keep going in the same branch. If not, let me know and I'll help you out.

9. React Lazy Suspense and Data Resources

Short description:

React Lazy Suspense is recommended for bundle splitting but doesn't work well with server-side rendering. Data resources can be created using the same principle as React.lazy, serving data if already loaded or throwing a promise to be resolved later. Errors with React.lazy and data loading can be handled separately. React doesn't provide built-in data loading support, but there are libraries like SVR, React-async, and Relay that offer it. A template by Ryan Florence can be used to create data resources, with additional types for TypeScript. The create fetch resource function fetches data and returns it as JSON, but it's not production-ready. The read function checks the cache for the requested data, returns it if available, throws an error if there was a previous error, and throws a promise if the data is still loading. This state machine determines the behavior.

So as I was saying React Lazy Suspense, really easy to use, works really well. It has been released some time ago and is highly recommended for bundles splitting. There is just one gotcha you need to be aware of is it does not work well with server-side rendering. So if you're using the standard Create React app and you're doing server-side rendering somehow, then it really doesn't work well. But I find most people who want to do server-side rendering are not using Create React app anyway. They're using Next.js and they've got their own solution for that.

So the next thing I want to take a look at is data resources. Because splitting bundles and loading code asynchronously is one thing and that's very useful. But loading data, Ajax requests for some JSON data, be it movies or users in the case of this simple application but pretty much every application needs data users to interact with. So that happens much more often and it turns out you can do it exactly the same way. You can create a data resource that follows the same principle as React.lazy does if it has whatever it needs because it's already loaded. It just serves it up. If it doesn't have it, it throws a promise and that promise gets resolved when whatever data is required becomes available and Suspense will re-render that component and it will work with whatever data it has. And of course I didn't mention errors with React.lazy but it's still an Ajax request so it could still fail. Certainly possible. So if an error occurs, then the promise is rejected and we need to handle that as well. We're just gonna leave that bit out for now. I'll come back to errors in a bit and we'll handle them. In fact, we're already handling them. The code is already in there, but I'll show you later.

Now, this is kind of the area where is it supported, isn't it supported is kind of fake. We're using data resources. And React itself does not provide any way of loading data. They basically said, well, you wanna use fetch find. You wanna use something else then fine, do whatever you want to do. React doesn't concern itself with how. So some people are waiting for React to officially ship supports for suspense with data loading. But React doesn't do data loading. So not quite sure what they should ship there. Now, part of the confusion here is if you go to the React websites and you look at loading data using suspense then it still mentions that this is experimental. Why? I'm not quite sure because it basically uses exactly the same paradigm React lazy uses and that works. There are several libraries that support this use SVR still will, well, revalidate React-async support it out of the box, Relay supports it, and I'm sure there are lots of others that support it. I'm not gonna use any of those. Not that there is anything wrong with it. I'm gonna use a gist, Ryan Florence created, that actually opened up on my other screen so let me move that over. So he wrote this like what six months ago it says at the top. And it basically is a nice template of how you could create data resources. Now this basically takes a function getPromise as the name suggests it is a function which returns a promise. And that basically does the work. I claimed this and I expanded it a bit. There is create resource.tsx here. Basically I've got exactly the same create resource here with getPromise except this is TypeScript. So it has some additional types here saying it is a function, which takes a string key and returns a promise of something. You can see exactly the same code in here but I've created a little wrapper saying well, usually what I wanna do is do a fetch, go and fetch URL. So I've got this create fetch resource which actually makes a resource around fetching data. It's a bit simple admitted it's not production code it's demo code but it basically does the fetch, it checks whether everything is okay and it's not frozen error. And then if the status was okay, so some 200 status, it returns to response as a JSON. Now I know that's a little short sighted there might not actually be JSON in there. It might be nobody or there might be text or XML or whatever in there. So as I said, it's not production code but it is quite usable and it's quite easy to build on top of it and turn this into production code. There are a couple of things I will change and I'll mention some of those later.

Okay, so how could we use that? Well, it turns out that it's really simple. You create a resource objects by calling that create fetch resource and we export that. Once that's done actually need to go here then we've got a resource object. So I'm importing it here on line four and then we call the read function on it, passing in the URL and it will return the data, but of course this is asynchronous so it doesn't immediately return the data. So what does that read function actually do? This is the read function. So it's going to take a look inside of its cache. So it's whatever you're requesting not undefined which basically means that we already retrieved that and it's loaded. So we're just going to return it. It'll type your typing so you get it as the right type but that's just a small detail. If there is an error associated with that item then it kind of means we previously tried to load it but something went wrong. So we've got an error. We throw that error. Kind of what you normally do with errors. You throw errors. Then there is this in-flight object. And basically any request which started which hasn't resolved or rejected yet so it's still busy is stored in in flight. So basically what we have in there is a promise. So here we throw that promise which is what react.lazy does internally as well. And that basically, this is the little state machine which basically determines what happens.

10. Fetching Data with Resource

Short description:

To fetch data, use the resource.read function. If there is no data yet, it starts loading. If it's busy, it throws a promise. If it's done, it returns the data. If there's an error, it throws the error. Create a resource object using createResource and export it. Use resource.read to fetch the movie data. Add a generic type for TypeScript. Remove unnecessary code and imports. Test the application to ensure it works. The same approach can be used for other data collections.

Go and fetch the data. So if there is nothing yet, we'll start loading it. If it's busy, we'll throw a promise. If it's done, we'll return the data. And if there was an error, we'll throw that error so it bubbles up again. So back to that code. This resource.read will either receive data, have an error thrown or have a promise thrown. If the promise thrown, the component is suspended and whenever that promise resolves, we're good to go. So let's go and create a resource. I'll create resource.tsx or.ts, obviously, it's not tsx file but tsx would have been fine. Import, create resource from. Create resource. Use this to create an object. And we'll export the resource. Except this doesn't work because it's not create resource. I wanted to create the fetch resource. Export default. Default with an F. So now we've got resource object. So now I could go, for instance, let's do the movie first. Where's my movies.tsx, there it is. So we say, we don't wanna do any of this, but instead we wanna use resource.read. Pass in the same URL. And that still needs to resolve. So what is this gonna return? Well, if everything is successful, it's returned something. Then that will be the data, the movie data. So it returns the data. Now there's a bit of TypeScript's here. We have to add a generic type. So it knows what type it is. Remember, if you don't like TypeScript, just put any in here and it's happy. So we don't have to err anymore. Well, that's because if an error happens, it will be thrown, not returned. So we can get rid of this. We don't have a loading state anymore, because again, if it's loading, then it doesn't return a loading state. It throws a promise and the higher level suspense object will catch it, the suspense components, so we don't need that anymore. So basically all of this just goes away. And the whole component is a lot simpler. We can get rid of imports. We don't need anymore. And I think my components, about half the size it was before. So let's make sure it works. Did I still have it open? Yes, here, let's make sure it's refreshed. Yes. So if I go to movies, we should see movies. We can't really tell that's their loading in a different way. No. We still see the request being done. Let's actually go back to the homepage and refresh this. Just look at the XHR request, so that fetch. We can see that it did the request. But what's different now, if I go to home, I clear the request again, go to movies again. There was no request. Why is that? Well, that's one of the shortcomings of the way fetch resource is set up right now, which could be very useful, just depends on your case, but basically if you do the same request again, it's gonna find the result in the cache and just return that. It's not gonna do another request. You can use a clear function to clear a specific item from the request, but by default, if you don't, it will just serve up the same data. Now again, depending on your application that could be fine, that might not be fine. You might end up serving still data or you might end up just saving HX requests for stuff that doesn't change or doesn't change very often. So we did movies. Let's do exactly the same for the, what is it's the users, there it is. Except this is users collection and a different URL. And all of that goes away. We can clear up the imports. Oops. And we do still need to resolve that. And that's user, not users. So do the same here for the user movie preferences. So this is going to return a single movie object with this URL. And all of that goes away. And I need to resolve this.

11. Handling Errors and Error Boundaries

Short description:

In this part, we introduced an error in the URL of the movies component, causing a 'failed to fetch' error. We explored how errors in suspense components are handled by error boundaries, preventing the application from crashing. The error boundary catches the error and displays a custom error message. We also discussed the nesting of error boundaries and their similarity to suspense. Now, let's move on to the next topic.

The user details is last one. I did something wrong there. I meant to copy these lines, but I had something else in my paste before. So let's make sure the application is still working. Make sure movies is still working. The users is still working. And the user details is not, because it looks like I forgot to import this. Did I do that with... Yes, that's okay. So, movies, users, user details, which wasn't actually what I was expecting, because this resolves a lot faster than I was expecting, interesting. That was more like it. It resolves faster because I actually opened it already. So, I hit F5 to make sure nothing was loaded. Now we see loading indicator. Now remember, when I first started the application that I said, when we get to user details, we do see two spinners and user's favorite movie always resolved first and loaded first. Well, there's little change here that doesn't happen anymore. We see one spanner and when it resolves, then both of those data blocks have been resolved. So we have changed the behavior of our application a bit. Now, personally, I didn't like the two spinners, but maybe we should have rendered one of the components a little sooner. Because one of the components had its data and could have been rendered before the seconds had its data. Because you might've noticed that there was this sleep parameter in various URLs. So specific movie loaded with one second delay and over here where's the sleep of 2000, so 200 milliseconds. And as the name suggests, sleep actually means that the server is gonna wait for that amount of time before it responds. That's why the second part of the data, the movie always resolves first. Kind of artificial, but that's the kind of thing that happens in real life. You don't know the order in which things resolved. I kind of make sure that they resolve in well-known order to make it recognizable. So using data resources, it actually really simple with little helper class like that. So please go implement this change in these four components, so movies users, user movie details, and user user details and create that little resource class or sorry, not class module to actually do those fetches. So I'm going to open up to breakout rooms again. There is a bit more work here. So I'm going to open them for 10 minutes and then I'll see you all in 10 minutes. So let me know if you get stuck with anything or something isn't clear. So see you in 10. So everyone's back. Sorry. So let's continue and let's see what happens if we have errors inside of suspense components because I mentioned that things could go wrong. We're doing Ajax request either for data or for Asian, this loading of components. So we're going on the network. Networks are unreliable, so things can go wrong. Well, let's introduce a little error. Let's go to the movies and let's say, I'll just introduce an error in the URL here. A couple of Xs in there, so pretty sure that's not going to point anywhere. And now if I go to movies, we get an error occurred, failed to fetch. That makes sense. What happens behind the scenes? Let's go to the code. We have our fetch resource. It does a fetch. Response state is just not OK. So an error is thrown. In here, that error is trapped, so whenever we try to read the resource again, that same error is thrown. Now what happens with errors in React components in lifecycle functions like when rendering, something like that, they typically bubble up. And if you don't catch them anywhere, it terminates your application. Well, in this case, as I already mentioned before, there is an error boundary. And a standard error boundary which catches all of those is going to catch this as well. Suppose I comment this out for a moment. So you run without the error boundary. And let's go to the homepage, open up the console, clear those messages. We see our whole application blows up. And where's nothing, it's completely unmounted to standard react behavior. Of course, normally in a development environment, you would get to standard react overlay showing you there was an error. The reason that's not showing up here is because I've actually hidden it. Where was I thinking? Yeah, that's this little hack basically that this hides the standard direct overlay error. Otherwise it would have shown up, but the application would still have been unmounted. So now this error boundary just wraps up and it displays our message. Just like suspense, we can nest those, nothing new here, standard error boundary stuff from react that's been around for quite some time. So the error boundary, it's already done so we don't really have to do anything here. You could add a second one if you want to, that's fine. Now we have to case, let me go to the code. Actually, let me fix this URL first.

12. Adding Parallel Suspense

Short description:

The application works, but when clicking on the movie or user, only a single spinner is shown. Both components still load their data correctly. If I add suspense boundaries to each component, we get back the original behavior with two spinners. By adding parallel suspense, we can control when the components suspend and resolve. It depends on the UI and desired behavior. Please implement this step and continue in the same branch. If you encounter any issues, refer to the previous step. I will open the breakout rooms for three minutes and we'll continue after that.

So the application actually works, it's kind of useful. I was gonna say, we've got this case where if I click on the movie or user we just see a single spinner where before we saw two spinners. Both of the components still load their data. They still resolve with the data just fine. But again, if I hit F5, a single spinner and only when everything is loaded, do we get the components. That's inside of the, what was it? User, no, not the user cards. Oh, it's just component used again. The user... Not the user movie details, the user details, this one. That's the one I'm looking for. It basically has those two components. They both suspend at the moment. Now they're both nested inside one suspense boundary, which means that that one suspense boundary catches both of these components suspending, and just says, okay, well, two suspensions in here, one results fine, we're still suspended. The second resolves, okay, fine, now we're no longer suspended, and we actually render. Maybe that's what we want, maybe it isn't, it really depends. But suppose we want those two spinners back, I could start adding two suspense boundaries in here, that doesn't fall back again, I need to finish this off, like that. So we've got one suspense boundary about the first components, another suspense boundary around the second component now. So they each have their own suspense boundary, and now if I go back here, I hit Refresh, we're back to that original behavior. Two loading spinners, the bottom one, the favorite move, it resolves first and we see the data, and then that user details resolves and we see its data. So by adding parallel suspenses like this, we can kind of control that's two components, suspend and resolve in parallel, and each has their own resumption points. Without these parallel suspense they basically suspend the same suspense boundary and it's only unsuspended when all of the child components are suspended. Either is completely valid. It's not like one is right, the other is wrong. It just depends on the UI. To be honest, I would not like this UI with two spinners, but we'll fix that in a later step. We are going to fix that. So just nest your suspenses, parallelize them as you need, as you want to get the desired behavior your application. So please implement that step. And if everything worked, you can still continue in the same branch like I mentioned before. If not, then right now we should be at step we are going to the parallel suspense. So the four data resources is the step we completed before this. So that could be the start branch. So this is a pretty easy step. So I'm going to open up the breakout rooms for three minutes. That should be enough. And we'll continue after that. So see you in a bit and let me know if you get stuck anywhere. Okay. So everyone's back.

13. Fetching Data Before Rendering

Short description:

In this part, we explore how to start fetching data before rendering components in a React application. By predicting the user's data requirements, we can initiate data fetching before the component renders, resulting in a quicker loading process. One effective method is to start fetching data when a user hovers over a navigation link. This approach makes the application appear faster, even though the overall loading and rendering time remains the same. To implement this, we can use the resource component's link and nav link functions, which can be triggered by onMouseEnter and onFocus events. By defining the data to load inside the components, we can ensure that the data fetching process starts when the user hovers over the corresponding link. However, there is a risk of unnecessary additional requests if the user hovers over multiple links without clicking them.

Okay. So the next bit, we're going to take a look at something which is a bit less technical and doesn't depend on suspense or lazy loading or data resources. You could do in any case. And it's about how you structure the way your application works. And what you typically see in a React application is what they call fetch from render. So you've got the components, it renders, it decided it needs some data. So inside of the render, you'll typically have something like a hook in there. It starts fetching the data, and once that's done, it renders again because state changes and the application sees, okay, I've got data or the component I should say, sees I've got data and renders the data. We're not using the hook anymore, but that still hasn't changed. We're rendering this components and only when this component renders do we do the resource.read, so request some data and the components suspends because the data isn't there. An AJAX request is done. Now, in many cases, that's just the way it is, but there are quite a few cases where we can do better and we can actually start fetching data before we render. If you can predict that the user is gonna require some data, well, you can start fetching it and do so before the component actually renders. So by the time the component renders, maybe the data has already loaded, maybe it hasn't loaded, but at least the request has started. So it's quicker to finish. And a perfect place to do that is when a user hovers over a navigation link. It's not the only one, but it's a perfect match. Like suppose I'm at the homepage here and I'm gonna go to movies, like I'm gonna move my mouse over movies. So it hovers over the movies link before I actually click and the data is there. Now with movies, it's not all that noticeable because it's pretty fast. But if I do the same with users, over over users and then I click and it only starts loading when I click the component is rendered. But when the user hovers over that user link, well, there is no guarantee he's gonna click it, but it is kind of likely. He's moved the mouse there. So at least he's considering it. So we could use it as a cue to say, well, okay, let's start fetching data. And then when he clicks and the user component renders, then the data might already be loaded or if it hasn't at least for already loading it. So the chances are that he's gonna see everything much faster. Is the application faster? No, we're gonna spend just as much time on the network to load stuff. We're gonna spend just as much time to render stuff. So your application is not faster, but it appears faster because we can start a long running stuff the asynchronous Ajax action, sooner. The same applies to others, but that's where we're gonna use it. How can we do so? Well, this resource component actually has a couple of other things. And if we go back to it, create resource. At the bottom here, it has two functions. And basically these are functions little components. So it has to resource link, and the resource nav link. And basically, those are exposed as link and as nav link. And anyone who's used react router before will know about link and probably also nav link because they're used quite a lot there for navigation. Now, you can see if I take link, for instance, resource link, it just renders a link object. It just passes on the props like before, except it adds to onMouseEnter and onFocus. So when I hover over it, the onMouseEnter fires, or if I tap to it, the onFocus will fire. And what it does there, it fires this preload function, which basically says, okay, go and start loading data. So as soon as you tap to it or you hover over it, it starts fetching it, that's data. It does mean it needs to know what data it is. So we define the data it needs to load, the URL in this case, inside of the components. So let's go and do that for users. So this is some request it's gonna do. Where is the NavLink elements, which actually goes there? Well, that's in here. This one, users. So if we import a resource from here and use resource NavLink, it complains because it says it's missing a cache key. Well, let's add that cache keys and cache key can either be a simple string or a collection. So fix up the closing tag. Now, if I go back to the application and let's make sure it isn't loaded yet. If I go to users and I hover over it, should I click there? Yeah, let's click there. No spinner, it's loaded immediately because it started while I was thinking, should I click there? Yeah, okay. By the time I decided I was going to click, it already did the request. If I just refresh the page to make sure nothing was loaded again, if I move over and do it quickly, I'll still see the spinner. But even this time, I saw the spinner shorter amount of time because I actually started loading data faster. I first want to go to home. But with the average user they'll move somewhere, they'll click and pretty much by the time they click, the data will have been loaded unless you're on a really slow network. Of course, then the impact is going to be not quite as big. Now there is a risk there. Let me open the network tab. Nothing to see there. If I just move my cursor over users, we've already fetched the data here. So if I just moved my mouse around over those links, I do start fetching data. So that's definitely a risk of doing additional requests, which were not actually needed. So let's do this same change here with this link that also needs a cache key with slightly different URL, but put this one while you look up the right one. So that's movies that needs this key. So I got my syntax right.

14. Adding Data Fetching to UserDetails

Short description:

In UserDetails, we render two different components, each making a Fetch call. We can put an array of items, such as the user and the movie, with different keys. By hovering over movies or users, we can see the AJAX requests being made. However, we need to ensure that the requests are added to the correct links and that any typos are corrected. This approach has the benefit of quickly displaying data, but it also carries the risk of unwanted requests and stale data. It's important to clean up the cache periodically to avoid these issues. Please add this change and let me know if you encounter any problems.

So we do the same in UserDetails except link is in UserCard here, resource.link endresource.link make sure that resolves. That also needs a cache key. But what are we gonna add in here? If I look in the UserDetails component, we see it renders two different components. Each of these does a Fetch. So that's one of them. And so I set this up in such a way that we can actually put an array of items in there. So we can say we want the user, which is this, the user, and we also want the movie. So two different keys. And now these values are slightly different. And this is the user.favoritemovie. So let's see if that works as expected. I hover over movies. And I was expecting to see an AJAX request there. Why did that not happen? What did I do wrong? It looks like you added it to the link for home and not the nav link for movies. Ah yes. You're right. Thank you. So that's where it should have gone and that should have been a regular link because that doesn't need to load any data at all. And it's still missing something. You will find, wow, you will find, oh, that was just a simple typo. So now if I hover over movies, it does. If I hover over users, it does fetch, they both fetch. Let me refresh again. I do the kind of user action you would expect, scroll down. That's the one I wanted to see. Well, the data is there almost immediately. And if I hover a bit slower, I wait a bit longer, then both those items have been resolved and everything's there. So I kind of like this approach. There is a risk of doing unwanted requests. So you have to be somewhat careful with this. It was also a matter of just getting a lot of stale data. So you want to make sure that you clean up those items in the cache periodically. Timing-wise, it's kind of hard to predict how long you need them. If you clean them up too quickly, you run the risk of deleting something from the cache while the user still hovers over it. And if you wait too long, you run the risk of showing stale data. So you kind of have to be somewhat careful there and figure out what's the right approach in your application. So the same thing. So please go and add this change. I'm going to open the breakout rooms for five minutes. And after five minutes, we're going to continue with the next step. So let me know if you run into any problems, need any help. See you in five.

15. Exploring Concurrent Modes

Short description:

In this part, we'll explore concurrent modes, which are not yet available in React. We'll discuss the challenges of rendering components in a single-threaded JavaScript environment and the delay between set state and DOM updates. We'll also examine the issue of event handling and the queue system in JavaScript runtime. Additionally, we'll consider the drawbacks of using multiple threads and the alternative approach of chunking operations to create idle time for the JavaScript runtime. Concurrent modes offer a promising solution, but their availability and implementation are still uncertain.

OK, so everyone's back. So up to this point, we've been looking at features which are available or usable right now. The last part of the workshop is about concurrent modes. And as I mentioned in the beginning, this is not available yet. We're venturing into future stuff, stuff which might change. Maybe, for that matter, it will never ship. We really don't know. Concurrent mode's been announced quite some time ago, but it still really hasn't shipped. So apparently, it is a pretty difficult thing to solve and get right. So you can't use this, but we'll get something like that. At least, presumably, we will. Until it ships, we can't be certain. But it does look very promising. And before I explain to you what concurrent mode is, we need to step back and take a look at what happens when JavaScript executes. And this says React rendering a component, and there is a set state and component rendering. But this isn't actually specific to React components. It's just how JavaScript executes. Because JavaScript is a single threaded environment. There is just one thread. And it basically executes until everything it wants to execute is done. And then that one thread is freed up for something else. So here, for instance, with that React example, we've got say, for some reason, a set state occurs. As a result, the components re-renders which owns the state. All of its children are going to start re-rendering. And when all of that is done, the DOM will be updated with the results. Now, I didn't draw 1,000 boxes here. But let's assume there are 1,000 components rendering here. And each of those takes 10 milliseconds. So we've got 10,000 milliseconds. So it takes 10 seconds in all between the set state occurring and the DOM actually being updated and all the code being done. Now, I know those numbers are a bit absurd. A React component which takes 10 milliseconds to render is really slow, really weird. That shouldn't happen. That should be much, much faster. But it's just for argument's sake and for demo purposes. Now, what happens during those 10 seconds between the set state and the DOM updated? A lot of code executes. But suppose a user comes in and clicks. So somewhere after the rendering starts, he clicks or is an event. And we've got this little green dashed box, which is the code we want to run in an event handler. Well, I mentioned JavaScript is a single threaded environment. So just a single thread, that means that that click code can't actually run in parallel with the other code. And the other code is running and it's not about to stop. So it just keeps on going. So when is that click handler event code actually gonna run? Well, only when all the original code is done. Basically what happens in JavaScript runtime is JavaScript runtime has a queue, asynchronous things like click events, user events, Ajax request finishing and code that needs to happen then is queued up. And whenever the current set of functions being execute is done, sorry, not to react, the JavaScript runtime looks in the queue. Is there any immediate work to execute there? So it picks up the first item from there, execute it. When that's done, it goes back to the queue. See if there is more work. If so, does it, et cetera. And that keeps on going until there is no more work and then to runtime goes idle. So nothing to execute. Well, if everything between set state and the DOM updating took 10 seconds and the user clicked after one second, basically means that he has to wait for nine seconds until his code handle runs, presumably that's gonna change some state in the application again. So we'd need to do some more rendering. So it's going to be quite some time before he gets any feedback. Is that a good experience? No. So how could we get around that? Well, the obvious thing which lots of environments do is say, well, if one threats problematic, we'll just create multiple threats and let them run in parallel. It's a possible solution, but leads to all sorts of problems with state being shared between threats, et cetera. So it's certainly not without its problems. In JavaScript, there is another way. We can start doing chunking operations. And that's basically saying, well, we've got some code executing, but instead of just executing it as one big block, that's chunked this up into smaller sections and basically give the JavaScript runtime some idle time in between the sections. So set state is cold. It renders maybe a few components and then it just sits there for a small amount of time saying, well, maybe something else to do. Nope, nothing. Okay. Then I'll go continue rendering. And then it waits for a bit. Anything else wants to go? No, okay. Then we'll continue rendering again.

16. Understanding Concurrent Mode

Short description:

ConcurrentMode introduces gaps in the rendering, allowing events to be prioritized over rendering. This means that the same component can render multiple times, and other lifecycle functions can fire multiple times. With concurrent mode, a component can render, be updated, and potentially be invalidated and restarted. Multiple render cycles can occur for a single update.

So if nothing happens, the whole process takes a bit longer because there are a couple of pause gaps in there. But if the user actually clicks, where does the user click events run now? Well, in the first pause, so it happens much faster. Now, suppose that just a console.log or something, nothing meaningful, and this is react, I should add that as well, then react can keep on going. Say, I'm going to render all the other components and I'm going to do the DOM updates. But potentially that click handler actually does a set state and invalidates all that rendering. So potentially it could say, well, we just rendered a bunch of components. Whatever they rendered, isn't actually valid anymore. We have to go rerender them. So that's what ConcurrentMode does. It introduces gaps in the rendering. So what are events can be prioritized over rendering which also means that same component can render multiple times or other life cycle functions for that matter can fire multiple times because as long as the whole rendering cycle isn't complete it could be interrupted, it could be invalidated and it could have to be restarted. So that's quite a change for components but there's now it's kind of like I've got a component it renders down that will be updated in the DOM and visible to the user. It renders twice then there will be two updates in the DOM. Well with concurrent mode, that's no longer the case. It could render then that's could be updated. It could render again. It could update but it's also quite possible that component renders and event happens that render is invalidated and then restart it. So you get multiple render cycles for a single update. Now, one way to see this in action is this demo. And that's not a demo I created. This is a demo, Dem Abermoff created. He's on the React team. He's been on the React team for quite some time now. And he actually did this demo in JFConf Iceland in 2018. So over two years ago. So that's kind of when they first announced this. And it's still a pretty good demo to show you what's going on, although the underlying code is outdated and tracking something from one screen to another is hard. So here's that same demo.

17. Rendering and Performance

Short description:

The longer the text becomes, the slower the rendering gets, and the charts may stop updating. This is a common behavior in complex React applications.

Now, what does this actually do? There's some charts here. There is an input here. And as it says, longer input, more components and DOM nodes. So basically these charts are updated and they're gonna show more data. And when does that happen? Well, that depends on the choice here, synchronous, debounced, or asynchronous. And synchronous is the current behavior. So if I focus the input and I start typing with a couple of keys, you see that every time I type, everything is updated and it's actually quite responsive. But the longer text becomes, I'm still hitting the keyboard now, typing characters, nothing happens. Now stop typing and eventually, there it is, it will catch up. Now we can make that a little easier to see. We've got this little clock, and as long as that's goes around smoothly and you see a small green triangle after it, then we know that everything is good. But let me do that same exercise. You see that green area starts becoming larger and larger, and it actually became orange, now we get red. And you see that it actually stops rendering occasionally. So that's a normal application behavior if rendering starts taking a long time. That's what happens with quite a few React applications which are complex.

18. Optimizing Application Performance and React Modes

Short description:

Debouncing is a technique used to solve the problem of an application locking up with large data. By waiting for a certain time period before firing an event, the application remains responsive. Asynchronous mode, now known as concurrent mode, allows for faster updates and interactive behavior by queuing and discarding work. Browsers refresh at 60 frames per second, providing a natural way to split rendering into smaller blocks. Legacy mode, blocking mode, and concurrent mode are different versions of React, each with its own set of features and limitations. React.strictMode can be used to check for invalid features in an application.

Now the typical way that's solved is using a technique called debouncing. And debouncing basically means that if an event occurs multiple times within a certain time period, say a second or half a second, then we're not gonna fire it. We're gonna wait until at least that time period has passed before we actually fire the event. So that's completely solved the problem with the application locking up with large data, because I can just keep on typing and our circle just keeps on going around the little clock and the green area keeps small. But if you look at the chart behind it, nothing happens. They're never updated. And so only when I stop typing, do they get updated. And if there's a lot of characters there, so a lot of notes, that kind of makes sense. But if there are just a few, you see I type a character now and it takes like half a second before the charts are updated. And if I keep on typing slowly, well there's plenty of time to update the components, but I'm sticking typing within the debounce period. So nothing is actually updated. So we get a responsive application, but a slow updating one. Even if it's not needed. Now what's called asynchronous here, they called it time-slicing asynchronous mode back then is called concurrent mode these days. And as I mentioned, the actual underlying codes probably very different now, but the principle of how it works remains the same. If I start typing and I type slowly, but within that half seconds, I just now see that everything updates and keeps on updating. And there's not really a slow down and everything kind of works. But if I keep on typing getting into the area where there are so many DOM nodes that it can't really keep up. And now it's not updating with every key stroke, it's updating whenever it's possible, but if it can't update within some key events, some key down events, then it's just gonna skip that update. So my application responds as fast as possible while still keeping it interactive, which is exactly what happens here. It does stuff and then if there's an event, it comes in and lets that event kick in, and then it keeps on going. If it can't finish what it does, it will discard some work and then queue it up again so it can do it later, and hopefully do as much as possible, keep it as practical as possible. Now in a browser, there are a couple of ways you could do this. But it turns out there is a real natural way for a browser, because a browser tends to refresh itself, at least most browsers do, at 60 frames per second. So, 60 times a second, the browser tries to draw a frame on, in the DOM. Now, that boils down to roughly 60 milliseconds between each frame. So if we can split these blocks up in such a way that they're inside of 60 milliseconds, then it's kind of like, if the user does something, it can happen almost immediately, and we've got really nice boundary. And there are some really nice APIs in the browser, like request animation frame, and inside an animation frame, you can request how much time you've got left inside of that animation frame. So that's the kind of code you can use to say, well, I start rendering here. How many components can I do? Well, if I'm here, I've still got eight milliseconds left. Okay, we can do some more. Here I've got four milliseconds left. We can do some more. And then where did my mouse go? Here, we've got one millisecond left. Now we don't have enough time left to render another component, so let's pause and start the next frame. So we get our pauses and we get all the interactive behavior. So as I mentioned, we're in Beta Land here. Be careful to not use this in production. Now the first thing you need to be aware of is this little chart. And this is always a bit painful. It starts here with legacy mode, and then there is blocking mode and concurrent mode. So what they call legacy mode is actually the current released version of React, but calling it legacy modes makes it sound dirty, like you're still using legacy mode? Well, no, that's the released stuff. That's nothing old with nothing wrong with it. What can you do in there? Well, you can use string refs, you can use the old version of contexts. This only applies to the old style context, not the new. That will still work. You can use find DOM node, another API, which is not very much used. So the first three are not very commonly used. And you can use suspense, which we already used. Now to be honest, we were using the experimental preview version of React, but that would have worked perfectly fine with normal React. All the other stuff behind this, so suspense lists, deferred values, interruptible pre-rendering, which I described, none of that works with legacy mode. Rendering is just one big chunk executing, no interruption, no priorities there, none of it. And no suspense list. There is an intermediate mode, what they call blocking mode. It's not fully concurrent, but it gives us some of the APIs like suspense list. Not a 100% sure why they include it, because it's kind of like, well, it's not the old stuff, but it's not a new stuff either. So it's kind of, well, it's on the fence, but it's only available in the preview version of React, the experimental version. So you can't use blocking modes in the current version either. If you could, it would kind of make sense, start adopting some of the new stuff, but no, you need to run the experimental version. And if you do, you might as well go to the full concurrent mode. So I've never actually done any serious experimentation with blocking modes. I go from legacy mode or the actual production mode, as I like to call it, that makes it sound better, to the concurrent mode. Now, what you lose is string refs, legacy context, and find-dom-nodes, but those are pretty old APIs which are not that important anymore. And you gain a whole set of things. Suspense, which we could use anyway, but you gain suspense list, which will show and will look at used transition, and a couple of other things. Now, how do you know your application is not using one of those first three? Turns out it's already checking. So, if I go to index.tsx, where is this thing, React.strictMode? If you run your application or part of your application in React.strictMode, it checks whether those components are not doing anything wrong. Those features are invalid, but also things like updating state from render functions, et cetera. So, in order to find that, it will actually double render all your components in development mode, not only in development mode, in production mode, this does nothing. So, it kind of helps you prepare.

19. Enabling Concurrent Rendering

Short description:

To enable concurrent rendering in your React application, you need to install the experimental versions of React and React DOM. These versions provide new features that are not available in the normal build. You can check if you have the experimental versions by looking at the package.json file. If you're running TypeScript, make sure to specify 'react-dom/experimental' and 'react/experimental' in your tsconfig file. Once you have the experimental versions installed, you can switch to concurrent rendering by using the 'createRoot' function instead of 'ReactDOM.render'. Pass the DOM object you want to render the application in as an argument to 'createRoot'. The prefix 'unstable_' is used to indicate that experimental features are being used. After making this small change, your application will be using concurrent rendering. Now you can start using new features like the suspense list and use transition to enhance your application's interactivity. Take a few minutes to make this change and if you have any questions or run into any issues, let me know.

Now, I didn't put this in. Nowadays, if you use createReactApp to scaffold out an application, it will automatically rep the whole application in React strict mode. But if you've got an existing application, which was created some time ago, that's probably not the case. So, I would recommend you add this in. If you get errors no problem, just rep sub trees, inside React strict modes would don't give an error and then fix the other places where you get errors and then slowly move more and more of your application into strict mode to prepare for the future. Do keep in mind that's live cycle functions are going to be called more often. So if you're doing performance analysis, you think it's running slow, then you want to disable strict modes. But for that matter, if you're doing performance analysis, you want to run in a release builds or React anyway, because the development builds do more work and in the release mode strict modes does nothing anyway, so there's no need to worry about. But if you're checking in development version, that's something to be careful with. So the different modes. Now, the first thing you need to do is do an npm install of React at experimental and React don at experimental. That will give you those new features. They're not inside the normal build. I already did that. So here inside my package JSON, you can see we were already running with React and React dom experimental features. So this was like three or four weeks ago that I added. So if you currently added, you'll probably get a different. You can't really tell how old or how new it is. And the version number is always 0.0.0-Experimental. And then there is some hash after that. I'm not sure if there's a meaning to that hash so you can decode it to a date or something like that. But to me, it's just like, okay, this is an experimental and I'm not really sure how old or new it is. If you're running TypeScript or there's something else you need to do. Got a tsconfig file here, which basically determines the TypeScript definitions. There is a types here. You need, and I actually need to check for a moment what it is. That was done. It's this one, you have to specify react-dom slash experimental and react-slash-experimental. Otherwise you won't get the new APIs. So react-slash-experimental and the same with react-dom. So with those, we can start using concurrent rendering. Oh, concurrent rendering. And it turns out the change we have to make to switch to concurrent rendering is really, really small. We go into index.jsx where it says react-dom.render. So this one, and instead of react-dom.render, we're gonna create a root object. So it works this create root. And you pass in the DOM object you want to render the application in, so kind of this thing. So let's grab that one. Let's move that over for a bit. So I wanna do a create root. By the way, you could see reset create blocking root as well for blocking mode, but I wanted to create root. I pass in that element and notice the prefix here. It says unstable underscore. So that's really to make it clear that we're using experimental features. It's complaining here because the typing says create root really wants a DOM object and get element by ID returns an element or no. So little TypeScript thingy, exclamation mark saying, I know better. I know this will really resolve to a DOM object and not null, so that error goes away. And with that, we can call.render on that root object being created to render our application. And that's the whole change we need. Here's the application. Let's make sure it still runs. Yes. I can go to movies, I can go to users, user details. We can't really tell that it's any different. It behaves exactly the same way but it is using concurrent rendering of React at the moment. So here's that same change in the slides. This is a gateway. This by itself makes would make a complex application more interactive but this application is pretty small so it's really unnoticeable. But now we can start using some new features and you'll get to do this first this small change. And after that we'll start using the suspense list and use transition to control how things transition in a somewhat nicer way. So let's go and do this. It's a pretty small change. So I'm gonna open up to breakout rooms for three minutes and after three minutes I'll see you all back here. So if you run into any issues, have any questions let me know, and otherwise I'll see you in three.

Now we've got concurrent rendering enabled, let's actually make use of some of those new features. And we're gonna use two, the suspense list. And after that we're gonna use, who called use transition, but first let's take a look at the suspense list. So, what's suspense list for? It basically lets you coordinate how different suspense components will work together. We've actually got a slight problem with that.

20. Controlling Rendering Order with Suspense List

Short description:

We have a problem with multiple spinners appearing and disappearing in the UI. By using React.UnstableSuspendList, we can control the rendering order of suspense components. Setting the reveal order to 'forward' ensures that the top component renders first and subsequent components render in order. We can also set the 'tail' prop to 'collapsed' to show only one spinner at a time. The combination of a suspense list with 'forward' reveal order and 'collapsed' tail makes the UI more predictable and user-friendly. The suspense list can be nested to provide different rendering behaviors for specific cases. Let's spend another four minutes implementing this. Once done, we'll move on to the next exercise with the use transition hook.

We've actually got a slight problem with that. Remember if I go to users and I click on the user, then we see those two spinners. Let me refresh this so it's actually a bit more apparent. We see two spinners for two different components because they both suspense. And for a while we had them in one suspense object, so they would both suspense and resolve at the same time. But that kind of meant that the slowest determines when we actually render something. And there is a clear difference. The one component clearly renders quicker than the other, but it's also the bottom one, which just happens to render quicker, which makes the whole UI a bit jumpy. We see two spinners, then the bottom one disappears and then the top one disappears. So, and that's the kind of place where using the suspense list makes sense. In this case, because of the explicit delays order in which they've resolve is actually deterministic, but normally that would not be the case. And you kind of want to make things more deterministic for the user and render in a more predictable way.

So, where would we add that? Well, we've got that user detail components and here we've got to suspense components and we kind of want to control those. So, what we could do is, say, you wanna use React.UnstableSuspendList. Again, it's unstable there because it's part of the future. I've got something wrong there. That's better. Now, this by itself, isn't gonna do all that much. If I refresh this, oops, it actually throws an error. That's because this was left over. So, now, we kind of see, not kind of, we see exactly the same behavior as we had before. Because SuspendList by itself doesn't really know what to do. A couple of props you can do. First you can specify a reveal order. And there are a couple of values. You can say together, which is kind of saying, well, they're all in the same suspense object anyway, just reveal them together. You can do backwards, which kind of says render the bottom one first and then the top one. But what I think makes more sense is render forward. So render the top one first and everything below that only afterwards. So we should not see the first, sorry, the second spinner disappear and then render something and then the first one. So now we see that, you see two spinners, but even though the first one takes longer to load than the second one, the first one actually renders and the second one, the favorite movie only renders after the first one. Now you actually see the spinner continue a bit here when the first component renders, which is a bit weird. I'm not sure why that happens because that first component does, render much slower than the second. So by the time that's finished, that favorite movie has loaded, the data is there. So it should be able to render right away. I'm not sure why that happens, but this is already nice or because now at least it renders from the top down. We're first rendering the top component. Then we're rendering the bottom components and the UI is better. There's another thing though, we still have two spinners. Do we really need to make it that explicit to a user that are two different components loading different sets of data waiting for that? Maybe, but probably not. I'm not saying you never want to do it, but there are lots of cases where you don't. So there is a other prop we want to set, Tail, and you could set it to collapsed or hidden. Not 100% sure what the difference is. I think we need the collapsed. Now you can see that there is only one spinner at a time. So there is one spinner while both components are loading. But only when the first component has finished loading the spinner is still briefly shown for the second component but they're never shown at the same time. Let me change this to hidden for a moment. Behaves slightly different. Now they kind of disappear for a moment. Which is not something I think is very nice. So maybe I'm doing something wrong here but I always find that the combination of a suspense list which reveal order forwards and the tail collapse makes the most sense to me. See one spin, the component render and only if it needs to, it will render another spinner for the second component, which in this case I'm still not sure should be required but it does. So suspense list, you can nest again, just like suspenses. In this case, it's all in one components, suspense list with two suspense components and direct the direct children of those actually suspended. That doesn't need to be the case. You can, again, nest these. You can put one at a high level saying, well the default I want for my application is this forward collapsed reveal style, but in specific cases I might want a different. Then you can mix and match as you want which is really nice, makes everything very composable and very tunable. So let's go and do this. Let's say, let's take another four minutes to do this. There isn't a lot of change. So we'll open up the breakout rooms for four minutes and let me know if you've got any questions. And once we've done this, there is one more exercise with the use transition hook but we'll do that after this one. So see you in four.

So everyone's back from the last exercise. So just the conclusion left and then it's a wrap which is good because we're just over time. The conclusion like suspense, it's released, it's probably usable. React.lazy perfectly usable really works well together for bundle splitting and there are many cases where I use it. Suspense with data fetching, quite usable as well.

21. Concurrent Mode and Suspense

Short description:

Maybe not quite as nice experience if you use hooks like use SVR or react async. Its main drawback is if you're doing server-side rendering then suspense is not really ready yet. UI approach from fetch before you render works really well. Concurrent mode solves a problem, especially for large applications. Using things like suspense lists and transition hooks help a lot. Suspense can be used for refreshing or updating paginated tables, but it's not a requirement. Thank you for being here. I'll hang around Discord for a bit to see if there are any more questions. Thank you all for being here.

Maybe not quite as nice experience if you use hooks like use SVR or react async. It's just a little configuration and it works too. Works really well. Its main drawback is if you're doing server-side rendering then suspense is not really ready yet. But if you're not doing server-side rendering, it's great. UI approach I showed from fetch before you render works really well is not dependent on suspense. So even if you don't want to use suspense and data resources, it's still perfectly usable.

Concurrent mode, really interesting. It solves a problem, especially for large applications but even small applications will benefit from it. Using things like suspense lists will make it much easier to control how different components show up after they suspend to fetch data, things like that. You use transition hook. There are things like, use deferred value. And there are more things coming along those lines. They help a lot. Are you gonna use those in small applications like say your to-do, the typical to-do application? Probably not. It's not that complex. It doesn't need that much coordination. It's not gonna have that much overhead with rendering so it's not really required there. But if you're building larger applications, yes, performance becomes an issue, having lots of different components, render spinners is not very nice. So having all of this coordination there is really nice. So I'm really looking forward to concurrent mode being released and being able to use that in some of the larger applications. So prepare for that by using strict modes in as much of your application as possible.

So I see one question in discord. What about using suspense mode and this type of request for refreshing or updating a list such as paginated tables? I'm not 100% sure if I understand the question, but if... Let's see if I understand it correctly. You're referring to, you've got a paginated table and you click on the more button to get the next page, et cetera. So will suspense make a difference there? Not by itself. I would still start using suspense and resources there. I would pretty much look at the UI approach from start fetching as soon as they hover over that more buttons so it's loaded by the time they actually click to create a better response. But suspense is certainly gonna help there, it's not gonna be a requirement again. So with that, I'd like to thank you for being here. Normally I would say you can follow my Twitter and I'll tweet out the slides and the demo codes, but you've already got all of that so there's really no need, but if you're interested in this will take you to the slide deck as well, but then again, you've already got it so not much point there. So I'll hang around Discord for a bit to see if there are any more questions and with that I'd like to thank all of you for being here. I hope it was a useful workshop and I hope you do a lot of interesting stuff with it. Thank you. Thank you, Harry. Thank you very much. Thank you, guys. Thank you. Thank you. Thanks. Bye-bye. Bye, you're welcome. Thank you. Bye, thank you. Thanks.

So Alexander mentions in this courts that Kenzie Dodds wrote in the blog post that one forward is used in the review or suspenseful risk tangos not even tried to render components after the most four words, one which would explain why the second spin are still appeared after the first component rendered.

Watch more workshops on 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 🤐)
React Advanced Conference 2021React Advanced Conference 2021
132 min
Concurrent Rendering Adventures in React 18
Top Content
Featured WorkshopFree
With the release of React 18 we finally get the long awaited concurrent rendering. But how is that going to affect your application? What are the benefits of concurrent rendering in React? What do you need to do to switch to concurrent rendering when you upgrade to React 18? And what if you don’t want or can’t use concurrent rendering yet?

There are some behavior changes you need to be aware of! In this workshop we will cover all of those subjects and more.

Join me with your laptop in this interactive workshop. You will see how easy it is to switch to concurrent rendering in your React application. You will learn all about concurrent rendering, SuspenseList, the startTransition API and more.
React Summit Remote Edition 2021React Summit Remote Edition 2021
177 min
React Hooks Tips Only the Pros Know
Top Content
Featured Workshop
The addition of the hooks API to React was quite a major change. Before hooks most components had to be class based. Now, with hooks, these are often much simpler functional components. Hooks can be really simple to use. Almost deceptively simple. Because there are still plenty of ways you can mess up with hooks. And it often turns out there are many ways where you can improve your components a better understanding of how each React hook can be used.You will learn all about the pros and cons of the various hooks. You will learn when to use useState() versus useReducer(). We will look at using useContext() efficiently. You will see when to use useLayoutEffect() and when useEffect() is better.
React Advanced Conference 2021React Advanced Conference 2021
174 min
React, TypeScript, and TDD
Top Content
Featured WorkshopFree
ReactJS is wildly popular and thus wildly supported. TypeScript is increasingly popular, and thus increasingly supported.

The two together? Not as much. Given that they both change quickly, it's hard to find accurate learning materials.

React+TypeScript, with JetBrains IDEs? That three-part combination is the topic of this series. We'll show a little about a lot. Meaning, the key steps to getting productive, in the IDE, for React projects using TypeScript. Along the way we'll show test-driven development and emphasize tips-and-tricks in the IDE.
React Advanced Conference 2021React Advanced Conference 2021
145 min
Web3 Workshop - Building Your First Dapp
Top Content
Featured WorkshopFree
In this workshop, you'll learn how to build your first full stack dapp on the Ethereum blockchain, reading and writing data to the network, and connecting a front end application to the contract you've deployed. By the end of the workshop, you'll understand how to set up a full stack development environment, run a local node, and interact with any smart contract using React, HardHat, and Ethers.js.
React Summit 2023React Summit 2023
151 min
Designing Effective Tests With React Testing Library
Featured Workshop
React Testing Library is a great framework for React component tests because there are a lot of questions it answers for you, so you don’t need to worry about those questions. But that doesn’t mean testing is easy. There are still a lot of questions you have to figure out for yourself: How many component tests should you write vs end-to-end tests or lower-level unit tests? How can you test a certain line of code that is tricky to test? And what in the world are you supposed to do about that persistent act() warning?
In this three-hour workshop we’ll introduce React Testing Library along with a mental model for how to think about designing your component tests. This mental model will help you see how to test each bit of logic, whether or not to mock dependencies, and will help improve the design of your components. You’ll walk away with the tools, techniques, and principles you need to implement low-cost, high-value component tests.
Table of contents- The different kinds of React application tests, and where component tests fit in- A mental model for thinking about the inputs and outputs of the components you test- Options for selecting DOM elements to verify and interact with them- The value of mocks and why they shouldn’t be avoided- The challenges with asynchrony in RTL tests and how to handle them
Prerequisites- Familiarity with building applications with React- Basic experience writing automated tests with Jest or another unit testing framework- You do not need any experience with React Testing Library- Machine setup: Node LTS, Yarn

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 Remote Edition 2021React Summit Remote Edition 2021
33 min
Building Better Websites with Remix
Top Content
Remix is a new web framework from the creators of React Router that helps you build better, faster websites through a solid understanding of web fundamentals. Remix takes care of the heavy lifting like server rendering, code splitting, prefetching, and navigation and leaves you with the fun part: building something awesome!
React Advanced Conference 2022React Advanced Conference 2022
30 min
Using useEffect Effectively
Can useEffect affect your codebase negatively? From fetching data to fighting with imperative APIs, side effects are one of the biggest sources of frustration in web app development. And let’s be honest, putting everything in useEffect hooks doesn’t help much. In this talk, we'll demystify the useEffect hook and get a better understanding of when (and when not) to use it, as well as discover how declarative effects can make effect management more maintainable in even the most complex React apps.
React Summit 2022React Summit 2022
20 min
Routing in React 18 and Beyond
Concurrent React and Server Components are changing the way we think about routing, rendering, and fetching in web applications. Next.js recently shared part of its vision to help developers adopt these new React features and take advantage of the benefits they unlock.In this talk, we’ll explore the past, present and future of routing in front-end applications and discuss how new features in React and Next.js can help us architect more performant and feature-rich applications.
React Advanced Conference 2021React Advanced Conference 2021
27 min
(Easier) Interactive Data Visualization in React
Top Content
If you’re building a dashboard, analytics platform, or any web app where you need to give your users insight into their data, you need beautiful, custom, interactive data visualizations in your React app. But building visualizations hand with a low-level library like D3 can be a huge headache, involving lots of wheel-reinventing. In this talk, we’ll see how data viz development can get so much easier thanks to tools like Plot, a high-level dataviz library for quick & easy charting, and Observable, a reactive dataviz prototyping environment, both from the creator of D3. Through live coding examples we’ll explore how React refs let us delegate DOM manipulation for our data visualizations, and how Observable’s embedding functionality lets us easily repurpose community-built visualizations for our own data & use cases. By the end of this talk we’ll know how to get a beautiful, customized, interactive data visualization into our apps with a fraction of the time & effort!