Server vs client components in NextJs 13 – When to use which

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
in this video we're going to talk about react server components and client components when to use reach and common patterns to interleave them together let's just start from server components now with the introduction of the app router which is built on top of react server component instead of rendering your whole application on the client side you can decide if you want to render your components on the server or send some JavaScript to the client and then run and render your components on the client side therefore you can combine the interactivity of a client-side application with an improved performance of a traditional server rendered application now if you look at a page inside of an application you would notice that most of the parts and segments and components on the page are static there's nothing interactive about them and they can be entirely rendered on the server using server components now for example here we have this nav bar up top which is a static component only this search bar on this side needs client-side interactivity or event listeners to listen to users interactions same as this sidebar here is entirely maybe rendering some links for you to navigate to different pages and we have some posts over here or whatever components that they may be and they only have these buttons that needs interactivity so as you can see we can keep a lot of these components and JavaScript belonging to these components on the server entirely and then only send their specific or necessary components that require interactivity to the client side now you may ask why would you want to use server components and make this complicated with a rendering client components or react on a client side anyways for the past few years what's up with the server components well the main reason for using server components is improved performance and that is because of three reasons first of all you can move your data fetching to your server side therefore you can use the infrastructure of your server typically your servers are going to be stronger machines with better internet compared to your users machines or Internet so you can fetch data there plus that you can be closer to your database so less latency of going back and forth between your server and your database so improved performance because of the infrastructure and lower latency and the second reason would be that you can now entirely keep the large dependencies that your app depends on on the server so any third-party packages that you're using can entirely remain on the server compared to when you use client-side rendering you'd have to ship all of those packages to the client side which increases your JavaScript bundle size sent to the client and because of these two reasons with server components your initial page load is going to be faster because all of the data fetching is happening on the server and the client is just going to get a generated HTML which is the result of your page and your data together and you're going to also ship less JavaScript to the client side so react code can be downloaded faster and your site or your page can be interactive faster now all components inside the app router or react server components by default all of your special files like Pages layouts loading and error and also all call logs created components that are living inside the app router are going to be react server components by default now if you need client-side components you can bring them in with the use of use client directive now client components enable you to add client-side interactivity as I already mentioned and the way you define them is with the use of use client directive you will put that use client directive up top of any module or component that you want to turn into a client component and that would create a boundary or Define a boundary between server and client now any other module or component imported into that file is going to also become a client component that's the reason why we cannot import a server component into a client component because once you have that use client directive up top that will Mark the boundary and everything inside of it nested down even to the children are going to become a client component therefore you won't even need to repeat this use client further down inside the components that are imported into this client component because once you mark this used client or the boundary once everything else further down imported into this client component is going to be automatically a client component now server components are guaranteed to only be rendered on the server and from a react perspective client components are rendered entirely or primarily on the client side however in next.js we know client components are also pre-rendered on the server so the HTML is going to be generated on the server and then the result is going to be hydrated on the client side or become interactive on the client side using react now when would you use which when would you use a server component versus a client component rule of thumb is to use server components unless you have a specific reason to use a client component and what are those specific reasons well if you wanted to add any interactivity and event listeners such as on click and on change anything that needs to interact with the user we would use a client component if you want to use react hooks or any custom hook that depends on react hooks use a state use effect or context you would use a client component another reason would be anytime that you want to access any browser-specific apis for example you want to access the window object over the intersection Observer these are only accessible in the browser so you would need to use a client component to be able to access them and the last reason why you would want or the use case why you want to use a client component is if you want to use a react class component now you might think that you barely need to use class components and you might be right the only use case that I can think of if your legacy application is not actually already written in class components the only other use case would be error boundaries if you wanted to create your own error boundaries you still need to use class components because function components or functional components do not support error boundaries or you cannot create error boundaries using functional components now in all other cases you're going to use react server component if you need to fetch data you can fetch your data or co-locate your data fetching with your server component on the server side anytime you need to access any backend service or sensitive information like tokens and environment variables you're going to use server components especially if you want to keep your large dependencies on the server instead of sending that JavaScript bundle to the client you're going to use or default to using react server components now let's talk about a couple of common patterns when you want to compose your client components and server components together to create your application now the first one is to move your client components as further down as you can to the leaves of your component tree so therefore next.js can optimize the performance of your application by rendering as much as possible on the server for example in this example that we had over here up top as you can see we have this search bar which needs to be a client component it needs client interactivity instead of turning this whole navbar or the whole layout into a client component just because this search bar needs interactivity you can abstract the interactivity logic of the search bar into its own client component and still bring that in or import it inside of your layout which is a server component so you're going to take that or bring that inside of a server component which is going to allow next to us to render your layout on the server and just plug in this search bar or client component to this whole server component now when composing server and client components together behind the scene react is going to render all your server components on the server it's going to then send the results of your server components to the client now during this stage if it encounters any client component is going to skip rendering it and it's going to create a little hole or a little slot for this client component once the result is sent to the client side these client components are going to be rendered and they're going to just be filled into this slot that was coming from the server merging the result of your server render and client render together now it will be the same if you're nesting a server component inside of a client component so your server component is going to be rendered on the server the result is sent to the client once the client is rendered it's going to then this result of your server component is going to just be plugged into where it needs to be plugged in and we know already that server components can only be passed in as children to client components so your client component is not even aware of what it is that is going to be rendered inside of its children it only knows where exactly these children is supposed to be rendered but once it actually gets rendered on the client side it just plugs in whatever that came from the server which is the result of your server component and it's going to plug it inside that specific slot that was left for your server component now as I mentioned already if you wanted to Nest a server component inside a client component you have to pass it as a children you cannot import a server component in a client component doing so will turn that server component into client component and if your server component is an async function it's going to throw an error so let me show you an example from the documentation here so imagine that we have this example client component that uses this used client directive up top and it's importing a an example server component inside and this won't work because you cannot import a server component inside of a client component instead you have to pass your server component as a children to your clone component so you're going to refactor your client component to accept a children you're going to have a slot open for any children that's going to be plugged in here now this happens to be a server component it can be also a client component so this client component is not even aware of what it is that is going to be rendered here it just has a slot open for a children and then inside of a parent server component for example inside of your page you're going to bring in your example client component and then you're going to pass your server component as a children to your client component this is exactly the way or the pattern that we're going to actually use to use react context or to share a global context inside of the app router or within the root layout because react context uses react Hooks and react hooks can only be used in client components so we're going to have a context provider just similar to this as a client component and we're going to plug in the rest of our application pages and layouts as server components inside of this context provider so we can share that context throughout our client-side components we're going to see this in action later on where we jump to the code and add a theme provider to our application to enable dark and light themes using the next theme library now next thing to keep in mind working with client and server components is whenever you're passing props from a server component to client components that prop or the value needs to be serializable it needs to be able to be converted to a string because you're crossing the boundary from the server to the client it has to travel over the network it needs to be converted to a string so things like functions and date can't be passed in directly that's something to just keep in mind if you're fetching data on the server side and passing data around in your server component they don't need to be serialized but anytime that you're passing it to a client component or crossing the boundary from the server to the client they need to be spherilized now to keep your server only codes out of your client component and your writing functions and modules that are only meant to run on the server to prevent them from leaking or be called or be imported into client components you can use the server-only package from the react team to Mark a file or a module as server-only code and anytime any function is imported from that file to a client-side component it's going to throw a build error let me show you the example here in the documentation so as you can see here we've installed the server only package this is from react and then you import This Server only package up top of a file for example here inside of our lib we have this data.js we are writing functions that may be fetch data connector database or CMS and whatnot and This Server only is going to mark this entire module as a server only module and if you import this get data function or anything from this module built inside of a client component it is going to throw you an error now the other pattern that I want to talk about is using third-party packages these packages can be UI libraries can be theme providers or authentication providers they often depend on react Hooks and react context to share that state or concern throughout your application and because this react server component and the app router is something new most of these third-party packages don't support react server components or they do not have this use client directive and you cannot use them inside your react server component you can still use them inside your own client components that have that use directive up top and that supports any react Hooks and functionality but you cannot use them directly inside your react server component so the workaround is to wrap those specific packages components coming from these libraries inside of your own client component so therefore they can have access to react hooks context and States and what not to work for example if you're importing a carousel an image gallery or an image Carousel from a third-party UI library that doesn't yet support the app router or this use client directive you can import it inside of your own client component that uses this use client up top and Export that component from your own client component so therefore you can use it directly inside of a server component for example a page component living inside of the app in this example now as I mentioned already some of these packages depend on a global react context provider to share this functionality throughout your application and we're going to implement this together inside of our project by adding a theme provider which is a global theme provider in the root layout of our application later on but before we get there let me just finish two things that I want to mention here we talked about passing props from server components to client components uh but when you want to share data between server components how would you go about doing them would you pass props from server components to server components uh or not now in server components there is no need to pass props between components back and forth for two reasons the first reason is that if you're fetching data for example inside your layout and you think okay I fetch this data in the layout let me just pass this data to my page component now there's no need to do that you can co-locate your data fetching with the component that actually needs it because next.js behind the scene is going to deduplicate your requests so any component can fetch data as it requires without worrying about duplicate requests because nextjoice is going to use the fetch cache if there is a similar request between a layout or a page so it's not going to call or fetch twice it's going to use that same thing so there's no reason to pass this data as props and for every other thing like logic and functionality you can use the native JavaScript modules for sharing these Logics between server components for example if you need to create a connection to your database you can use the Singleton pattern natively in JavaScript modules to create a connection to your database and then share it between any other react server component or module that needs to connect your database and needs to use this connection so to summarize to share data or functionality and logic in your server components we're going to use native JavaScript modules and patterns like Singleton pattern or for Fetch and data requests we're going to co-locate the data fetching with the component that actually requires that data without worrying about actually sending multiple requests because nextges is going to use the cache and it's going to avoid sending multiple requests now let's jump into the code and see how we can use react context inside the app router to share a global theme inside of your whole application okay let's go ahead and apply what we just learned about composing react server components and client components by creating a dark theme for our project here I'm going to use the next themes package for this matter so let's just go ahead and add the next themes package I'm going to open up the terminal stop the dev server and I'm going to run pmpm add next themes let's now restart the dev server so the way next themes package works is that we have to wrap our entire application with this theme provider that we get out of this next themes package so let's just go ahead and try to import this inside of our root layout where we are actually rendering the root layout of our application so I'm going to import this over here and then I'm going to try to wrap my application with this theme provider we just import it from the package so let me just cut this off go down the footer and actually render this let's go back to our application and see what's going on here now as you can see this doesn't work because as I mentioned most of these third-party packages rely on react context to share functionality throughout your application and react context or any other react hook for that matter is not supported inside your react server component and a root layout is a react server component as you can see on the error here too it says create context only works in client components which root layout is not a client component it says add a used client interactive at the top of the file to use it now we know root layout cannot be a client component if this was any other layout besides the root layout we could have just added a use client up top of this file but we also learned about another pattern and that is to move our client components as farther as possible or deeper as possible inside or down in the tree of R components rather than turning the whole layout into a client component if you're going to abstract the logic that we want into a client component and the nest decline component is still inside of a server component so we're going to do something similar over here we're going to create a file called providers this is going to allow us to share any context that we need so we're going to export a function from here that called providers up top I'm going to say that this is a client component so use client so therefore I can actually use react context and instead of importing this theme provider there I'm going to import it here now this provider it's a client component and it does accept a children I'm going to remove this theme Provider from my root layout and I'm going to actually bring this over here and I'm going to actually bring it right over here and inside of here I'm just going to render my children so what are we doing here let's just review together I am creating a provider's component which is a client component therefore I can use this third-party theme provider that depends on react context inside of it and I'm wrapping my children inside of it now the pattern we just learned about nesting server components inside client components is actually what we're doing here so this theme provider that comes from this package is a client component and we are nesting or passing children to this theme provider or to this client component now these children are going to be our layouts or pages that can also be server components so that's the only way you can actually Nest server components inside client components we learned that we cannot import server components into client components and if we do they just turn into client components once we pass that boundary between server and client but the only way we could do is to just pass them as children and that's what we're doing here so going back to our layout now what we can do here is to bring in our own client component that we just created called providers and then we're going to wrap our layouts with this custom client component we created now our application should go back to how it was working with the difference that now we have access to this theme provider now the way this next themes package works is that it's going to set a data theme attribute on our HTML tag which we can read and style our components differently using CSS now for styling we are using Telvin CSS so let's go to Tel Link and see how we can support dark themes inside Telvin now as you can see here Tailwind actually includes a dark variant by default so out of the box what you can do is to prefix your classes with this dark variant and then if it detects a dark theme it's going to apply these classes now the way that it's going to understand if it needs to apply the Dark theme or not is by reading a class attribute on a parent element so first we need to set a dark mode class inside of our Telvin config.js so let's go ahead to tell when config.js and create this dark mode to actually reflect on the class and the way that it works is that now inside your HTML embody tag for example we have a div that has a background of white and a dark variant of background or black now right now there is no Dark theme applied so it's just going to read the background of white now if you pass in a class of dark to a parent to this div or if we want to apply it in the whole application we'll pass it to our HTML tag and a class of dark now it's going to tell me it's going to read into this class and then apply this dark variant now inside of next theme we can actually change so that instead of setting a data theme attribute it actually sets a class on the HTML if you scroll down to the API section to the theme provider you can see this attribute prop that you can pass into the theme provider defaults to data theme but we can actually set it to class so let's actually go back to our providers and pass in an attribute here and say hey instead of data theme we want to set a class on our HTML tag let's go back to our application and see if this is happening let me make this a bit bigger let me just refresh the page and as you can see there is a class of light set on our HTML tag right now we are in the light mode or the light theme so there is this class and this style set on our HTML tag now that everything is set up how do we actually go about changing this theme so the next theme package actually also exposes a hook called use theme this is going to give you the resolved theme as well as a set theme function that you can use to toggle between different themes now the use theme is a custom hook that uses react hooks under the hood so we need to implement this in a client component so where would we implement this let's actually go back to our layout and we have this header component which is responsible for rendering that header up top so maybe we want to create a button right up top there that allows the user to toggle their theme so let's go inside of our header this is still a react server component and let's say the idea is that we want to create a theme button over here so I'm going to say theme button let's just go ahead and create this inside of our components maybe down in the UI I'm going to create an EU theme button component we're going to export a react component from here that also include the use client directive up top so that we can actually use the use theme Hook from the next theme package so what we're going to do inside here we're going to get some stuff from this use theme hook and primarily what we're looking for is what the resolve theme is so what the current theme is and then the set theme function inside of here let's just render a button for now and inside of this button I'm going to look at this result theme and I'm going to say if this include if this equals dark let's just render the text light and in all other cases just render the text dark so for now you're not doing anything we just want to render the text light or dark depending on our resolved theme let's just go back inside of our header and try to import this component we create together so let's just save this up let's actually also turn this container into a flexbox I'm going to say item Center and then let's say justify between to put that dark button now if I click on this nothing is going to happen because we haven't hooked this button up so I'm going to add an on click method to this and then once this is clicked I'm going to call this set theme function and I'm going to say if again the resolve theme equals dark I'm going to pass in light and if not I'm going to set the theme to dark let's now test this together now if I click on this button it should turn our application to a dark theme we have to change our header so that it reflects this but you can see we're toggling the theme using this use theme hook inside of this button now if I go back to my header and actually remove this background of gravy sets earlier so it toggles with our Dark theme you can see we have our header now actually also toggling with this theme instead of having a set background now as you may have already noticed when I'm toggling this theme the next theme package is actually toggling the value of our class attribute on the HTML so when we turn it to dark it is actually setting it to dark which is then picked up by telvind to apply the dark variant now let's actually make this button look a bit nicer than just saying the text there for this I'm going to use hero icons package so let me stop the dev server and I'm going to install as a Dev dependency these hero icons let me just actually also show the website here now this is a free SVG icon library from detailing team and we're going to actually use this here inside of our application so let me just restart the dev server going back to our button let me just copy this little code snippet I have written before and let's explain what we're doing here again I've just added some classes over here on click we're still setting the theme based on what the current resolve theme is and then instead of just rendering text we are rendering these icons the Sun and Moon icon here and we're just also import these icons from the hero icons package and now if I go back to the application and refresh you should be able to see a little nice button there that allows us to change the theme now if you can see hardly that little icon the moon icon showed up there but this is not actually quite working correctly because we are in the dark theme right now and if we are on the Dark theme we are supposed to show the song icon now the reason for this is that nexj is actually pre-renders client components on the server and there's no way for us to know what the theme is on the server therefore this use theme hook actually fails to read the correct theme and messes up this theme over here so therefore we should not render this theme button unless we are mounted on the client side now you might think well this is a client component and react renders client components on the client side but again next.js take this a bit further and pre-renders our client components on the server for a faster experience and then hydrates that HTML with react on the client side therefore it also runs this client component on the server and that's why there is a mismatch of the resolved theme over here so to make sure that we are only rendering this theme button if we are on the client side we're going to use State and let's create a mounted and set mounted let's just initiate this with false I'm going to also use use effect from react and we're going to use this to set the mounted to true and we're going to also only run this one time and down here I'm going to say if I'm not mounted I actually don't want to render this theme button I'm just going to render all let's actually also get the user State okay now if I refresh our application choose show up correctly now that I'm in the dark theme the actual Sun button which is on the dark this sun icon is going to show up to say hey turn to uh light mode and then turn to dark mode now this is something to keep in mind it is next GSS specific because it tries to pre-render our client components on the server for a better performance and hydrates them on the client side you have to make sure that you're only rendering this theme button if you're actually mounted on the client side which you can do with the use of this user State and use effect to make sure that it is actually reading the correct result theme because when this renders on the server side there is no way of it reading the theme so that's where the mismatch comes from now furthermore if you actually check your console you should see this warning about extra attributes from the server and the reason is when this root layout ran on the server there was no attributes set on our HTML tag but when it ended up on the client side it actually had this class as you can see down here and style tag added to the HTML so the HTML that was rendered on the server is different with the HTML that's now on the client side because next theme actually went ahead and added these attributes to our HTML tag so that we can toggle the theme now to solve this you can pass in this attribute that says suppress hydration warning now this is going to actually get rid of that warning as you can see over here if you go back to the next themes package you can see they are also recommending to use this attribute on the HTML now sometimes you cannot really match the attributes that you get from the server and on the client in this specific case there was no way for us to know the theme on the server so that we can set the correct attributes on our HTML tag and if you actually also read the react documentation they explain that you can use this attribute anytime that's kind of impossible to match the htmls on the server and the client but they also recommend not to go ahead and you overuse it unless there is a specific reason why we cannot match the attributes from the server and the client that's a wrap for this video folks if you talked about react server component client component when to use which and how we can actually compose them together we also looked at using react context inside react server components by implementing this theme using the next theme package if you have any questions hit me up in the comments if you're interested in learning next JS this was an example lesson from my course there is a link in the description you can check it out let me know if you have any questions and I will see in the next one bye
Info
Channel: Hamed Bahram
Views: 25,834
Rating: undefined out of 5
Keywords:
Id: 3Dw6D_WuzSE
Channel Id: undefined
Length: 34min 7sec (2047 seconds)
Published: Sat Jun 17 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.