React Server Components: A Comprehensive Breakdown

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
you all have a lot of questions about server components and I get it it's a really different model especially if you're already familiar with react and obviously if you're not I think it's important that we break down the very core of how they work and how they differ from the existing react model thankfully Josh comeo wrote an article doing this and I spent the last hour going through it piece by piece recreating a bunch of the examples and breaking down how server components work on a fundamental level while also answering tons of questions from people in chat so hopefully you can find some value in this long rant cuz I put a lot of work into it I think it's a pretty good one so without further Ado let's dive in thank you Josh comeo and thank you agore for sharing this earlier making sense of react server components so here's something that makes me feel old react celebrated its 10th birthday this year this is also interesting on my behalf because react started in 2013 but I started writing react in 2018 so I'm now square at the halfway point for react I have now been around for exactly half of react's Journey in the decade since react was first introduced to a bewildered Dev Community it's gone through several Evolutions the react team has not been sh shy when it comes to radical change if they discover a better solution to a problem they'll run with it a couple months ago the react team unveiled react server components the latest paradigm shift for the first time ever react components can run exclusively on the server this word exclusively is important here because this is a part of thing people seem to miss a lot I know I did initially with things like remix or next your code would run on the server so you'd send HTML down to the user but you would also send the JavaScript to for all of the same content so you were required to then also run that JavaScript on the client to recreate the Dom to link the virtual Dom to the real Dom and because of that any code in your component that runs on the server is also running on the client the beauty of the new model is a component by default only runs on the server and doesn't send JavaScript to the client anymore which is really interesting there's been so much fraking confusion about this online lots of folks have lots of questions around what this is how it works what the benefits are and how it fits together with things like serers side rendering I've been doing a lot of experimentation with server components and I've answered a lot of of my own questions I have to admit I'm way more excited about this stuff than I expected it to be it's really cool so my goal today is to help demystify the stuff for you to answer a lot of questions you might have about server components to put react server components in context is helpful to understand how SSR works if you're already familiar with SSR feel free to skip to the next heading this is what I described before user would receive this is the good old empty HTML file that I talk about a lot with just the script tag and then the script loads runs and then you finally get page content and this just explains the bundle gets mounted includes react and other dependencies once the JS has been downloaded and parse react brings into action but this all happens when you're staring at a blank white screen or if you put some default Styles in here which almost no one does you have a tiny bit of additional content some sites like twitch have a crappy skeleton that is the default HTML and then the script comes in to take over but this is all the user sees for a while and this is usually not the content you want the user to see and depending on if they have JavaScript enabled or not how fast their internet connection is how fast their device is and so many other things that might be a long time they have to sit there and wait for what SSR does is it does that first run of the JavaScript on the server so that you get sent more useful HTML content it is not the HTML that includes just that JavaScript tag and nothing else it's instead the HTML after react does its first render and update but then you have to get the JavaScript to work and that's hydration which Dan Rob describes as watering dry HTML with the water of interactivity and event handlers so you have your static HTML with a bunch of elements in it and react has to run the way it always does to figure out which elements bind to which components so that it can continue to own and update that HTML page once the JS bundle has been downloaded react will quickly run through our entire app building up a virtual sketch of the UI and fitting it to the real Dom attaching event handlers firing off effects Etc that's AAR in a nutshell we talk about Cesar we typically imagine a flow looking like this user visits a site no JS or something like that receives the request renders the react application generating HTML sends that HTML to the client and then the clientes over from their hydrating and rendering but there are other ones where what are they specifically explaining here when we build the app yeah so you can also at build time generate different HTML files for every route and then load JavaScript to take over once the page has been fetched but usually what we're talking about with SSR is the server side part this would be more like using the next export function which I've argued against many of time next export should not exist because most of next's features especially now in the server component world require next's server and its relationship with the client and if you throw that all away for static HTML files it's no longer really nextjs the way I see it serers side rendering is an umbrella term that includes several rendering strategies they all have one thing in common the initial render happens in a server runtime like node using the react Dom server apis Yep this is very fair server side rering always means running something like react Dom server on something that isn't the client but usually what we're referring to is this pattern bouncing back and forth this is about data fetching using something like react query or SWR Apollo the client will make an equ work request which would then grab data and send it back so this is just what happens if you use fetch at all but with these tools you can cash those calls better prevent having to dup them and a lot of other useful important things yeah server sends files to the client well it sends an HTML file to the client which then us to download the JavaScript render the shell request more data which goes to the database well it goes to the server that then goes to the database and then that comes back to the user as Json which then can be rendered by the JavaScript to make HTML there's actually a lot more steps here I like that he simplified it but this really like like he went out of his way to simplify it here there's like seven steps uh where each of those arrows are Reas an imaginary madeup timeline everybody gets so mad at me when I do stuff like this them it's really helpful I think this is a good thing to do it makes it way easier to read and parse first graph shows the flow using a client side rendering Strat starts with a client receiving HTML then it's a download with a script tag run y we've explained that enough times you've seen this for a lot Airbnb starts rendering a shell or one I was mentioning before we'll turn my network speed down to slow 3G we're going to go to Twitch see all of that with the loading spinner and this stuff all here that's all happening while the JavaScript gets fetched and then runs so in some amount of time once the like 20 Megs of JS finish fetching I pick slow 3G for a reason we'll finally have some js running in the next couple minutes yep now the JavaScript is started to run but you see there specifically before the JavaScript is here it has this state because right here it's fetching all of the JavaScript so this is just the static HTML anyways the user will see the loading State until the network request resolves and react reenders replacing the loading UI with the real content as we just saw with twitch let's look at another way we could architect This Server client yeah server renders the shell so there's some work being done here so there's more time until the client gets their first response but less time until they see something valuable but then they still have to do the same download JS step the same hydrate step the same database query and the same content render a shell is better than a blank white page but ultimately doesn't really move the needle in signific way yep totally agree this isn't useful because it makes your site faster this is useful because it allows you to have a better loading state and better like default templates depending on how much of your shell you choose to render so here is where he puts flags for time to First paint and content painted these are the flags that you'll see in things like Lighthouse and other performance testing tools where it labels different points in the user's Journey when the page loads if we render a blank HTML page that then loads JavaScript to trigger loading States and then get data once the JavaScript loads the loading States and has rendered those on the page we hit first paint cuz that's the first time content of meaning is and painted on the page once the server has sent back the Json response and we've parsed that and made that into HTML with react then the content is painted and we hit that flag so the difference with SSR is that first paint happens much earlier we get some content way earlier and the page interaction still has to happen like after the fact and then the database query and then the content is painted but we get something to the user earlier at the cost of a slightly later page interactive depending on if this render shell is statically cashed on the CDM or not but it's fair to say it's basically the same thing and just first paint is moving I I can agree with that doesn't this feel a bit silly when I look at the SSR graph I can't help but notice the request start on the server instead of requiring a second round trip why not do the database work during that initial request so why not fetch these things immediately and then the page will become interactive later so you have content painted before you have page interactive this is what like deep SSR does when you fly SSR the page and its content you're able to send the correct page down first try with none of these additional States at the cost of additional time until the user sees anything I was hoping you'd have the interactive chart again because the catch here is that your first paint gets delayed based on how long it takes to do these things so if your database query takes five of his imaginary unit you just delayed the first thing the user sees by that five amount so if you want the user to see something and you're okay with the right thing the right content coming a bit later it is very nice to do this later but if you want the user to get the correct content first try as fast as possible then you would do the database call on the server the problem is depending on the SSR model you're using this can be really easy or really hard it gets difficult to say hey I actually want this section to be loaded on client and this section to be loaded on server and if you change your mind down the road it can be really painful this is the beauty of the new model which I'm sure we'll go into in a bit especially when streaming gets involved first paint content painted pag interactive yep yep yep instead of bouncing back and forth we do our database query as part of the initial request sending fully populated UI straight to the user how we do this we need to be able to give react a chunk of code that runs exclusively on the server to do a database query so this hasn't been an option even with SSR kind of with something like trpc you could actually specify that a query is SSR ready and when it does the server side render with that hook it can block get that data and Pull It in on that first render so there are solutions before server components that let you on server's Pass Run server code and on the client's pass fetch data from server this has been figured out we have had Solutions I'm not going to say they're anywhere near as good as RC but we did have this option in react because yes components render on both but you can have the code that they run trigger differently depending on which environment the code is running in but oh I'm going say this we've come up with lots of solutions next and gats you have created their own ways to run code exclusively on the server I should have just scrolled down get serers side props this code only runs on the server and then when you access it on the client it's data that exists in the top level props route I will say get serverside props is one of like the worst patterns I've ever used and I'm so happy it is dead because this encourages terrible things it's like that awful pattern of wrapping your app with context but 10 times worse because there's no type safety there's no inference for anything and you have no guarantees that the props you return here actually make it to a component anywhere in your application because this is defined route level and things have to be passed through so your components underneath don't actually know if they have access to this regardless it worked but rappers like trpc doing this at a different level ended up being a much better experience in my opinion I have a whole article on my blog that I never plug one of my first articles that did really well and I'm proud as hell of this one and Inc consistent truth nextjs in type safety this article is not the case with server components but if you're still using page router is specifically if you're using get server side props it's so bad uh yeah next can be a type safety risk we have this get server side props that returns user and then we call props do user.name but if we do anything between these two which there's a lot of room to do do this data might not make it here in particular if the document or app TS or jsx files don't pass props properly to the page component this won't come through if these are in different files you have no guarantees and this doesn't actually have a type definition at all this is all coming off of any as I said here there's a number of type errors this silently allows if you modify the schema you select different values in that Prisma call you change the key erroneously delete something for some reason they use implicit any for all of this stuff we can manually type the props but then they can still drift so here I only select ID even though we think we have the whole type that fails their INF ferget servide props casts a bunch of to any yeah it just it's overrides to key string any which is awful it also INF first to props never and we've thankfully moved on so yeah I have a whole article about that if you want to learn more about the the type level failures within gets overside props there's also structural issues for how it gets called and where data goes there's a reason that next has moved on to something much better yeah gssp was a mess the r is super ahead of its time let's see if we agree on the problems only works at Route level yep meta framework came with approach GS be yeah all react components will always hide the client says nothing about the misery that is the type safety story regardless it was awesome that we had a solution caught on for a reason next blew up before rsc's were even a thought and that's because of how much better these patterns were than having to touch everything on client but here's where stuff gets interesting server components the thing you click the deal for at a high level react server components is the name for a brand new paradigm in this new world we can create components that run exclusively on the server so all us to do things like write database queries right inside our components I remember the first time someone posted an example like this everybody was freaking out like oh my God you're going to allow so many sequel inject sending that code to the users because it was so hard for us to comprehend that this code only runs on the server this is the equivalent of in something like rails defining a template this only runs on the server this file effectively is an HTML template generator that is the magic of rsc's is you have an HTML template generator intering with react the client library and you can move between the two as you please yep he even said as I was saying before this code looked absolutely wild at first and it did it took me a bit to process that this only ran on the server function components can't be async we're not allowing them to have side effects and render like that this is an important piece server components never render this code breaks the traditional react model in that sense like this code will not rerun when you render on client and if you have a client component that was past the server component as a prop that it renders inside of it and then that client component reenders that child won't reender that's a huge win and if you do get an update from the server with new markup for those server components it can render those through react with something like router. refresh in next which allows you to directly update those static non-updating components when the server sends updated HTML this means a big chunk of API incompatible server components you can't use State you can't really use react context you aren't going to run something like a use effect as a side effect there really aren't side effects in server components which is nice too CU I found a lot of the time we're bringing in things like use effect and other side effects it's to get data to our components which is a whole like a significant portion of why we have side effects in our apps so if we have a different way to get that data without needing side effects that is a win even though if you when you first look at it it might feel like a cost because now we have part of react where we can use the solutions we're used to that's cuz it lets us not reach for those Solutions when we don't need them yet so components themselves are surprisingly straightforward but the react server components Paradigm is significantly more complex this is because we still have regular old components and the way they fit together can be pretty confusing this new paradigm the traditional react components we're familiar with are called client components yep I've been on this name forever should have been interactive components server components only run on server client components render on both here's how I summarize it RSC is the name for the Paradigm the standard re components we know and love have been re branded as client components it's a new name for an old thing it works just like client components worked in next and remix before where they run on both server and on client new paradigm has a new component type called server components these only run on the server the code isn't included in the JS and they never hydrate or re-render yes this is the distinction going to just hold and let yall look at this and read it a few times if you don't get it yet pause and think a little bit longer on it this is the core of server components it's important that we understand the way things worked before that is client components and server components are this new thing that doesn't follow the model we're used to they don't run in your client and we can interrupt between these things the way we would before with a a template that runs in a server that then triggers JavaScript on the client but with a much happier story relating these pieces react Ser components are not a replacement for server side rendering it's SSR version 2 two separate puzzle pieces yeah we still have server side rendering to generate the initial HTML it still runs your client components once to make that proper scaffolding but a lot of the content can be fetched as server components and you don't need a lot of those behaviors on the client you don't need to make those API request you don't need to do a lot of those things they even have RSC examples without SSR which means similar to with SSR where you could use it as a build step you can build the react server components ahead of time and have those be fetched effectively from a CDN to hydrate your app it's just a weird pattern I haven't seen a compelling use case for it yet but I could see them in the future for sure compatible environments traditionally you could just install the latest react version to try out a new feature server components are not that simple because it has to be integrated with a lot of things it's the bundler the server runtime the relationship between those there's a lot of pieces that have to be assembled just right for this to work he says here the only recommended way to start with rs's right now is to use the newest version of NEX 13 hopefully in the future more react Bas Frameworks will start to incorporate server components feels awkward that a core react feature is only available to one particular tool the react docks have a bleeding edge framework section where they list the Frameworks that support server components actually curious what's on it right now not recommended for production as a March 2023 I wonder how salty the team is on that they don't have anything else under here yet that's not surprising but interesting regardless I'm excited to see more Frameworks using server components I Know Remix is working on it I believe Astro was for a B I don't know how much of a priority that is at the moment but there's a lot of places trying to to make good server component Integrations in their Frameworks in the new react server components Paradigm all components are assumed to be server components by default this was a controversial decision that I think was the right decision and as he says here if you want the old Behavior you want a traditional client component use client if you move all of your code from Pages directory over to app router and you want to just have everything work the way it did before you can code mod go add use client onto every TSX file and it will behave the exact same way as it used to which is really powerful but the server components don't have those behaviors and you can fetch directly within them really really powerful the standal Ling at the top use client is how we tell react this component is client components we don't need to specify use server in our server components use server is used for other things which we'll get to in a while but for now use client it's similar to use strict for strict mode JavaScript but it's they're trying to follow the way these things have been done before so which components should be client components I like this framing if a component can be a server component it should be a server component and that's why it's the default because server components are much simpler and easier to reason about because they don't rerun you don't have to mentally keep track of logic updates and state it just renders the right stuff it's almost like previously with function components before hooks you always wanted function components if you could because they were sfc's stateless functional components and when you don't have state in a thing that you don't need it becomes much simpler this is also why HTM X is so dope because it significantly reduces the amount of State you're thinking about managing and interacting with in the client and in your code less state is good and I think that's a theme you're going to see with a lot of the technologies that we'll be talking about and building over the next few years this is the the anti-state and kind of the anti- API wave that we're seeing happen they're talking about like page interactive time and stuff here it is cool the sunless JavaScript like less state is good because less state is less surface area for problems shouldn't make it our mission to eradicate as many client CES as possible we shouldn't try to optimize for smallest number of client components it's worth remind that until now every component in every app has been a client component it absolutely makes sense to have a lot of client components still and if you have something where like you have one client component and you could break it up into two to make it easier you should and if you have a server component and it needs some behavior that is better to do on client you should move it there yep that's all stuff I agree with boundaries one of the first questions I had when I was getting familiar with rsc's was what happens when the props change for example suppose we had a server component like this suppose initial render hit was Zero component will produce the following markup what happens when hits change it would need to reender but it can't server components don't make sense in isolation this is I think the part that is making it harder to digest server components with hooks you could start at any point in your app you be like okay I'm going to add this component here and we're going to use hook for it and it would just work in an old react app as long as you update the react version with server components it only works from the root so that top level mounted component the thing at the very very top of your Dom that has to be ready for and support server components and as you add rsc's and these patterns throughout your app it has to start from the route down so it's not anywhere near as easy to adopt or even think about because we're not just thinking about an isolated component and a different way to do things within it anywhere in your tree we're thinking about the root of your app and how it sends data and updates through your entire application it's a fundamental change in how we do the stuff let's say we have the following component Tre app header article hit counter discussion comment comment if all of these were server components it would make sense but let's say article component owns the hits State article is used client and this has the used State call in it and then hit counter is a sub component see the issue when article renders any owned components will also render including Hit And discussion you server components though they can't the react team has added a rule client components can only render other client components unless you pass a server component is a prop which we'll get into in a bit for now assume this is true there are catches but but this is true one of the biggest aha moments I had with server components was the realization that the new paradigm is all about creating client server boundaries yeah I push this really hard it's all about the boundaries and the relationships between components it lets you control the boundaries of your components similar to how hooks let you control the boundaries of your state so here is a client boundary because this is a used client component so all of these are client components because they're mounted by a used client component when you add the use client directive to the article component we create a client boundary yep yep yep when I first learned that client components can't render server components it felt pretty restrictive to me what if I need to use State high up in my application does that mean everything needs to become a client component turns out in many cases we can work around this limitation by restructuring our app so that the owner changes I'm going to do a quick demo because this doesn't show some of the things I want to show here's our hello world make a component in here in this components folder we'll do counter. TSX first thing use client use client because it's going to have state in it next export cons to counter give it some hints there we go so now we need to mount this in the server component so I will pass this here and import and we have this and it works as expected we click it and it goes up but let's make another component quick we'll do a server only. TSX Sport async function Su server component and in here we want to do something async what I'll do is make a text file text.txt make sure it's actually in the root and I'm going to put hello world from file in here so I'm going to prompt first read from text.txt with node FS well sure return div text cool this should work I could just import FS the normal way import FS from FS it's not even async whatever this will do what it needs to so if I throw this in here we would all expect this to work and it does this is now reading from a file and this is happening on my machine because this text file isn't being bundled so if this can be accessed that is happening on the server so it could be a database call it could be anything else but here I'm mounting that there let's say I want this in this component though like I have div class name equals Flex Flex call BG gray 400 or 300 cool I'm just going to wrap this like this for now html's hard cool so now this is gray where's that semicolon coming from oh here and I'm going to give the button some class names click too cool so here's the button but let's say we want more space around it and we want this text above in there P6 so let's say we want the text instead of there inside here let's try it let just mount it some server component okay cool we're mounting this in here oh no can't resolve FS What's Happening Here well it's trying to render This Server component on the client it's trying to bundle this in the and send that as JavaScript to the user that they can run and they can't but I want this here how do I get this here well I'll show you we will pass it a child the smart enough come on react Element Make It optional this can't run on the client we can't Mount this directly in a client component the key word there though is directly so I can render any react node as a child or it could be another prop I don't even need to name this children could be anything else but I can pass that node as a child so let's do that counter and now it works because this server component is still being rendered on the server when you pass this as a child it's still being rendered here but react is now smart enough to know if you're rendering a server component as a prop to a client component that it should run that on the server and serialize the thing it's passing so this component doesn't get another JavaScript component to mount this component is receiving a property of some server component I found this can sometimes be easier to understand if I change it to something like some sub component so this is just named whatever you want the reason I'm changing this so I can show it this way CU I think this helps people understand the difference a little bit better I forgot to save there we go the the point I'm trying to make here is as long as the thing that does this call that actually puts the brackets around your server component if that happens any server component you're good even if you're passing that as a property to a client component and this allows for some really powerful weaving of these things without compromising on the core value of server components which is nothing comes from a used State call nothing comes from a hook there cannot be a hook above a server component that passes props to a server component every server component has to be renderable on server in that first pass so every piece of data it needs needs to be there as part of the request so it can come from your cookies it can come from the URL headers and parameters it can come from parts of the request and characteristics of it it cannot come from a component in the State on the client side specifically this pattern is really cool I see why he didn't include it as early cuz this is where like the Mind exploding stuff starts to happen but it is so powerful it's so powerful let's go back to the article cuz I'm almost certain he's going to touch on all of this peing under the hood let's look at this at a bit of a lower level when we use a server component what does this output look like what actually gets generated we run this function in the react server component Paradigm all components are server components by default since we haven't explicitly marked this as a client component it will only render on the server so when we visit the page we receive HTML that looks like this has hello world and then a baked in script tag that basically tells react where all of these things are so it knows how to update it if it gets new changes in the future it's restructured things here the true generated JS inside of an RSC us a stringify Json is an optimization to reduce the file size of HTML yeah he also say stripped out noncritical parts of HTML yeah this is a really good sample of effectively what you get back from that really simple example we see that our HTML document includes the UI generated by a react app the hello world paragraph below that we have the script tag that loads the JS that's so it can hydrate and other client components can run on the client side and then we have the script with this inline JS what we're doing here is telling react hey so I know you're missing the homepage component code but don't worry here's what it rendered this allows for react to hydrate and and know what is where without having to actually have that code to rerun and full so this is what each of those server components returned in its props so that react's traditional virtual Dom model can still have what it needs to Mark each component and where it's from and what it has without having to send you all of the JavaScript to rerun that on your own side we send along the rendered value the virtual representation that was generated on the server when react loads the client it reuses the description instead of regenerating it very handy a fun comparison for this is something like if you do a use a effect that has a fetch call and you theoretically got that to run on server in order for the client to hydrate it would have to make that same call and you have to wait for that additional network round trip in order to have the same state on the client as the server another problem that I'm sure we've all had the the dreaded hydration error HTML doesn't match one of the most common cases I have for that is date times if we render on the server and when we render on the server the date time it renders is UTC and when I render it on client it's PST then we get two different strings out it might be 4 p.m. in one time zone and 6 p.m. in the other so if we run the same JavaScript on the server and the client the output might be different which causes a hydration error but if we don't run that JavaScript on the client we just pass the returned value to the JavaScript it prevents those types of hydration errors and desynchronizations because the code only have asked to run once yep okay let's see what the advantages that he lists are for ACT server components this should be R is the first official way to run server exclusive code in react so I mentioned earlier though this isn't really a new thing in the Bro react ecosystem we've been doing things like this since 2016 the big difference is we' never had a way to run the server exclusive code inside our components this is the magic being able to await a data datase call or a file read from the server or just calling something like reddis directly it's really powerful oh he does have the before and after for this so yeah here he shows the page interactive time goes down a good bit this maybe less exciting because most next steps are already fast enough with page interactive timing here's something I find really cool though we no longer have to make the same compromis in terms of features versus bundle size it's a very fair point your bundle size is no longer going to be as affected by what you're including in a lot of places here's a fun one in upload thing we have different patterns that are not generated but we have a a set of SVG patterns and colors that are randomly selected based on the name that you chose for your app so that you can have a visual distinction between your apps we just thought it was a cute thing to make your dashboard a little clear which app is which if we were to bundle all of those svgs that file would be like 500 kiloby and we put them in the JF because we want to be able to dynamically affect values like the fill color so if we were to have done this traditionally with client components we would have ended up fetching so much JavaScript we didn't need because we would have had every single SVG that could be rendered on the client as part of that bundle but since these svgs are actually server components you only get the ones that are rendering on your page we would have had to do some crazy stuff to get this to render correctly so that when you first load the page it comes through and doesn't have to fetch these images in the background or something because we include them in the markup because we can do that without exploding our bundle with server components that's just one of many examples of things that were surprisingly easy for us because we're using the new model somebody said react's had lazy loading for years that's not lazy loading can I ask you sincerely like what's not clear so I can clarify it this isn't lazy loading there's nothing lazy I'm command shift ring right now this is a full refresh with no cash and this content is here this is in the HTML this is an embedded SVG G this isn't lazy loading this is there on the first render without having to fill up the JavaScript with a bunch of stuff the SVG this one is there as Json but I have 50 svgs I have a bunch of svgs can I explain this more sure I'll explain this more okay let me pull up the code quick here's the thing that you couldn't do before see this function get random pattern Styles this function is in a 500 line of code file full of these different svgs all is Json this is a shitload of code that I would ideally not ever have to send to my users this one's even string escaped in a way that um my editor doesn't seem to like much whatever this file is huge and it sucks but I don't need the content of this file all this file does is defines this SVG that's all it does so now instead of having to load this whole file or people keep saying what about code split what about breaking it up cool I could have made a different file for every one of these svgs I could have made a dynamic import structure that will import just the ones that are rendering right now and then when the page loads on the client what I'm going to have to do is load the page with no svgs load the JavaScript that determines which svgs to load that JavaScript goes and dynamically fetches the however many svgs I need and then finally 5 to 10 steps later I can finally render the SVG or I know this this is crazy thought absurd what if it was just there in the HTML what if I didn't have to have 15 Steps between the JavaScript rendering the SVG and the HTML having the SVG what if I didn't have to build a new import solution what if I didn't need 15 layers and instead the server code which the server has a lot of code it can have as much code as it needs cuz it's a server I don't give a crap the server runs this huge file it picks the pieces from that file that are needed puts those in the markup and now it's done it doesn't need this code file it just needs two of the values from this code file thank you prime I'm very happy you're here because this is one of those crazy like horseshoe Theory things where like the heavy front end people and heavy backend people we all get why this makes sense I think I've been very clear with this it seems like svgs are triggering people so I I'm going to be very clear about something svgs are text based markup like this is HTML you shouldn't have to re-encode this like okay somebody's upset because this means you have to reload the SVG yes you have to reload the 50 bytes correct it's a really simple example but let's say you have a heavy component there a lot of stuff for UI but only renders like a little bit of it I I'll make a really simple example let's make a component named heavy. TSX export async function some heavy component and this takes in a prop if not props do is signed in return div please sign sign in first and then after here we return div pretend this component has a bunch of stuff that is megabytes of JS bad so in this component if the user not signed in we get this tiny bit of HTML back if the user is signed in we could get like a bunch of subcomponents that are really heavy we could get any of many different things could even be like we do a a long waiting async call here there's a lot of things you might want to do later somebody said why not code split that because then you have to load another JavaScript bundle okay I think this is where things are breaking down Let's Pretend This was lazy loaded so we have some const fake lazy equals react. La doesn't exist pretend it does so let's say we do this here is how this would work on server to client so step one server sends client empty HTML with JS tag step two client parses HTML and fetches JS three client runs JS to determine what to render step four client fetches additional data JS or whatever else it needs to complete render five your page is rendered so in the case of lazy loading what happens here step one we get the empty HTML with the JavaScript step two we load the JavaScript we load a small bundle of just the things that are above lazy loads that the root JavaScript the client runs that JavaScript including running this check in some heavy component if you're not signed in then we render this if you are signed in we return fake lazy so here's where things get problematic because now there's a break here where I now have to specify 4.1 load lazy JS 4.2 run lazy JS 4.3 hope it doesn't depend on more lazy JS 4.4 realize it does load even more js on and on and on until eventually you have everything you need to to finish your page render because of this what you'll usually end up doing is putting a suspense around it with a loading state so as we wait for all of that additional JavaScript to come in we have a fallback equals div loading for the import suspense so now we get significantly more back and forth between the server and client we have to have an additional loading state to wrap the thing being loaded in lazily or it's going to block render entirely and we have to fetch all of this additional Java script and pars it just to put a thing there with server components you don't have to do any of this let's redraw this with server components now step one server gets request runs react code to generate HTML client renders HTML with correct content fetches JS to hydrate three before we had a whole bunch of steps when we broke out a lazy loaded thing with loading States and all these other p pie in order to make sure we're not sending a bunch of JavaScript to the client that they don't need now if they don't need the client JavaScript they just don't get it we just render the right thing on the server and just send the correct markup if you only need the JavaScript to render the right markup that doesn't happen anymore we don't have JavaScript that includes 500 svgs in it we just include the svgs in the HTML it's really cool for most projects it's fine if it takes a few seconds for react to hydrate yes and again to the point I was making before if we're waiting the few seconds for react to hydrate that time where we're not seeing the SVG if we lazy loaded it anything that's under a lazy load doesn't appear until the project has hydrated that's a huge cost and if you're willing to block every asset in all of your pages sure but the point here is I didn't have to write any special code I wrote the obvious code when I did this for the upload thing code base we took all of our svgs we put them in a file we added a function on the bottom that randomly selects one and a color based on the name of your um project like this doesn't get included in the bundle because it doesn't need to it's really nice but here's something I find really cool we no longer have to make the same compromise in terms of features versus bundle size yeah you just you don't think about this it's a server rendered component you don't have to worry about these things you just render it on the server prism is a fantastic example prism is a massive library and if you're using this in pre- react server component land on like nextjs you're going to end up in a slightly rough spot where you have to wait for all of prism to load on every page even if you lazy load it you still have to wait for it to load on pages that use it in order for the hydration to be completed proper syntax highlighting library with support for all popular languages would be several megabytes far too large to Tak ajs bundle in order to make this work we to trim out languages and features that aren't Mission critical or critical oh that's really cool somebody made a new code syntax highlighter just for this I'm sold this is the sort of thing that gets me excited about serving compon yeah absolutely something we're excited for in the future with upload thing is the ability to get all of the traits of an upload so like what types of files does it allow how big of files does it allow all baked in in that first server render so your upload button appears immediately with the correct expectations and behaviors all data that it fetches from the server based on your API keys this is all stuff that's entirely doable using these new models this is a really cool Library it's one of my favorite examples so far of like why this model is so powerful because you don't have to worry about how big the serers side bundle is you just render it on the server it's not about performance in uxi after working with RSS for a while I've come to really appreciate how easy breezy server components are Yep this is the thing I think people Miss we do have more things in the new model this is the problem space of a react application I'm going to call this use effect we'll say this is context a much smaller one here and I'll call this one use State and other simple hooks so this is obviously not all of the complexity of react there's a lot of other things you have to be considered of so let's say horizontal is complexity to understand and vertical is complexity to debug I'll even call this like foot gun iness with core react features how hard is it to understand the thing and how much can it foot gun you this is with the old react model the foot gun index yes I think this is where people get frustrated on one hand all of these things still exist but we're going to say Asing components as like the first piece these are still complex to understand if you're used to the old model but they're not too complex to understand but where things get really magical is how hard they are to debug and how foot gunny they are there's still the foot gun that if you render them on client it can do some weird but generally the foot gunness is significantly lower but we don't just have Asing components we also now have to deal with the concept of a server component as a whole and server components again like take a bit to understand I'd say about as long as took me to understand the basic hooks like you state the foot gunness on this is even lower I you can do client component which will be like the same but slightly bigger because this is the thing that we're used to but the the use of the word client and the breakdown of the relationship there is not the most intuitive thing passing rsc's to client components this I'd say like it's complex to understand but there really isn't too much foot gunness with it so what's happened here is we have spread out horizontally to the point where we have slightly more things to understand but there is so much less foot gunness now this is the the difference I really have been trying to highlight is the likelihood you blow your foot off with the new model is significantly lower and even if the amount of complexity you have to understand to jive with this model is higher you can compose these pieces in a way that ends up being less complex almost always because chances are you're not touching all four of these things in a given feature if I'm adding a new component that renders user data I'm probably just using these two and then if I want to have a button that has an onclick behavior that requires me understand some of this but probably not even all of it and I probably don't need to touch this part at all the result is that for most features most changes most of the work that you're doing with this model the amount of complexity you're facing every day and more importantly the complexity of debugging and identifying and fixing issues is exponentially smaller and that's why this model is so cool once it clicks because things are so much easier to reason about yes there are more parts and people don't like when this horizontal gets longer because it makes them feel left out it makes them feel like have to work harder to be where they were yesterday and people don't like when the bar gets raised without their permission especially if they don't see the benefit but they're so focused on this horizontal complexity of just the number of things they have to know that they're forgetting about the vertical complexity of how much it sucks when the thing doesn't do what it's supposed to this is the magic of the new model I'm pretty much entirely agreeing with Josh it's that about performance in ux along with yep ultimately so very early days only emerged from beta a couple months ago so really excited to see how things evolve over the next couple years Community continues to innovate Solutions like bright take advantage of the new paradigm Etc this is what I was waiting for this is when the new model gets way cooler if we go back to the lazy stuff from earlier this kind of is like this is a replacement for the lazy loading patterns that is comically more performant because we don't have to do multiple trips to the server to get data so we get the first paint as soon as we send something so we can render the shell send that and then start the query after sending it how can we do that we already sent this don't we have to do a new request no HTML streaming comes in clutch here get into that in a bit it's beyond the scope of the tutorial but you can learn more about the stuff on his GitHub oh he doesn't actually show it in here so here is the diagram Josh Drew and we're going to make it a lot worse first we're going to do the lazy loading model so here server sends HTML and client renders HTML fetches JS and this part can be an unknown amount of time depending on how fast their Network in their devices and then after we've done that we have to parse the JS run JS DET turn DET what else is needed and let's say at this point we determine that we need one more JS file and one more API call that then requires another JS file so let's say we'll just do the lazy load then API we determined we need another file so go to the server again return lazy JS file and there's some time between these cuz there's Network time and then run query determine what else is needed and we realize we actually need to make an API call we do this API call just actual work that has to be done and the server respond to API call with data which might take a bit or we'll even we'll we'll do a query here so par request and then we have a separate like database query step we'll make it blue just using blue as work DB query and then parse response render correct HTML this is an example with a waterfall if you're not familiar with the term waterfall means something that takes time triggers completes and then something else that takes time triggers from the completion so in this case we ran the js on the client once it fetched we realized that it mounts a component that needs more JS that's lazy loaded so we get that lazy loaded JS it comes in we realize that we actually need to make an API call using that JS so we make the API call we parse the request we get the DB query run we get our response and then we send that to the client which then has to parse it and then render the correct HTML using react so the code for this would be pretty simple that's some component does a query fetches some stuff I forgot a string close there and we return div data. we don't want to load all the JS for this so instead we grab it lazily so the page loads it renders lazy some component which then triggers the JS fetch so the HTML was sent to the user it has nothing but a JavaScript tag in it so we load the JavaScript tag which has this in it we run the JS we determine that we need to lazily load this so we go to the server say hey we need this additional file the server sends us that additional file we now have this JavaScript to run so we run it we realize that it's missing this data because of this use Query call so we run that fetch call after we loaded that additional Javascript file and then we return the HTML then but we have to wait for the server to parse our request run that query and then send the response so I don't think that's ideal let's look at the new model quick this is where streaming comes in first off this determine what else is needed that's not a thing anymore most of that doesn't exist anymore the return lazy file doesn't exist the par request doesn't exist I mean I guess it kind of does CU it might be data from the cookie so let's say we immediately respond with some static HTML or whatever our like top level is and then we stream in additional stuff after we can identify user here that's just JS I should say renders HTML skeleton and it we'll say send HTML skeleton here and while that happens this is all happening in the background as the user renders this content and then when this query is complete we even say it takes longer than it does it will then stream down the additional data is part of the same request that is render complete page so we get that skeleton almost immediately the same way we did before after sending that response we can keep running these things in that same server node in the background and once that's done we send a new response with the additional data it's so much easier to manage I can show what this looks like if you're curious it's actually pretty easy to do instead of counter let's render some slow component so we have some server component we're going to change this or I'll just export async function some low component perfect if I mount this component and pretend again that this promise is something that work that your server is doing it's a query that you're doing it's data you're fetching it's something meaningful I'm just doing this cuz I'm lazy and we go in here and we render this in fact we can even leave some server component here so we render that and then we render the slow component if we go my Local Host what you'll see is the page is taking 5 Seconds to load but it has all of the data in it immediately but what if I wanted the user to get get Hello World from a file before they got the slow component what if I wanted you to get this first have a loading state for this and then this comes in that is now trivial because we can use suspense for much cooler things than lazy loading I can yoink this fall back equals div doing work and now the page loads immediately I refresh page loads instantaneously you can see the loading spinner still going because the main HTML response is still streaming down but we have content rendered that's meaningful and if we look at the network tab so you can see that response initially has different content that it ends up with because with HTTP streaming we're able to send part of the response and then send the rest later this means if you have a bunch of react components on your app most of which load very quickly but you have one that you notice the data takes a while you just wrap that in suspense and you're done this was never this easy to structure before where the Thing You Do by default is really simple and works really well and as soon as you notice something is slow you wrap it in suspense and you're done it's so clean and simple and easy to work around and the result is significantly more performant because you're not waiting and doing a bunch more back and forths I saw the question coming up a few times isn't this more work for the server though no it's absolutely not because previously I'd respond from a server to send the HTML the client would run some stuff it would go back to the server and say hey I need more JavaScript the server would process that request and respond with more JavaScript then the client would run that JavaScript realiz he needs to make an API call and go back to the Ser say hey I'm sorry last time I promise just give me my Json the server processes your request again generates a new response and then sends that new response and then now the client has the response with this model you process one request you don't parse additional headers you don't need to you don't terminate more responses than you need to you don't spin up more lambdas than you need to this is a DB call too and if we assume that these DB queries are the same size which like let's be fair the one for the API is probably bigger because it's over fetching do you see how much less work has to be done on the server then has to be done here yes any one of these blocks is smaller than the block here but we're not talking about the number of blocks we're talking about how much work is done total and if you look all of these certainly add up to be a lot more than the one request response process here the only reason this would be slower is if for some reason HTTP streaming was significantly slower which it isn't or the code that turns your Json into HTML is particularly slower compute heavy which it isn't doing one pass with something like react to take a bunch of data and turn that into HTML is really fast those aren't real costs yeah I just I I don't buy the argument that this is more expensive it just it isn't you end up making so many fewer API calls that this ends up being significantly cheaper and I can promise you as someone who's built apps on both the amount of time of compute that each of these is using per user way less server comput is running on the new model almost always for me I think this makes it very clear how much better the new model is I should draw some arrows to make it clear that that response becomes the content but specifically the server can send a response keep doing work and then send more response later and all you have to do as a Dev to consume that is wrap the slow thing in suspense this doesn't change when this code runs the slow component still runs as soon as the page load starts so it's just better that ended up being a lot more than I expected but I think it communicates a lot of the stuff I've been trying to server components are a fantastic model and I think if you take the time to dive in and understand you'll be really impressed with what you can do with them thank you Josh for the wonderful article thank you agore for recommending it to me on stream and if you want to learn more about why I love this so much I'll pin a bunch of videos on the side here all about my favorite Parts about server components and some of the cool things they change about my thinking thank you guys as always really appreciate it peace nerds
Info
Channel: Theo - t3․gg
Views: 59,378
Rating: undefined out of 5
Keywords: web development, full stack, typescript, javascript, react, programming, programmer, theo, t3 stack, t3, t3.gg, t3dotgg
Id: VIwWgV3Lc6s
Channel Id: undefined
Length: 52min 41sec (3161 seconds)
Published: Thu Oct 05 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.