When to Use Client Components Instead of Server Components

Project Source Code

Get the project source code below, and follow along with the lesson material.

Download Project Source Code

To set up the project on your local machine, please follow the directions provided in the README.md file. If you run into any issues with running the project source code, then feel free to reach out to the author in the course's Discord channel.

This lesson preview is part of the Next.js Complex State Management Patterns with RSC course and can be unlocked immediately with a \newline Pro subscription or a single-time purchase. Already have access to this course? Log in here.

This video is available to students only
Unlock This Course

Get unlimited access to Next.js Complex State Management Patterns with RSC, plus 70+ \newline books, guides and courses with the \newline Pro subscription.

Thumbnail for the \newline course Next.js Complex State Management Patterns with RSC
  • [00:00 - 02:04] Welcome to the last lesson on this module. Today we're going to see how and when specifically you might want to go for a client component rather than using a server component. The first thing to remember is that in next rendering on the client is an intentional choice essentially. You opt in to rendering on the client or essentially using client components by the use of the use client directive. We already saw that at the beginning of this module. This explicit decision gives you the power to determine whether a component should come to life on the browser or not. By understanding when and why to do this we can create a more optimized and tailored user experience. And again this all ties back to the concept that we saw on the first module of page architecture. This is an intentional choice which means you have to think about how you want to structure your page, where the interactivity, where the user, the immediate user feedback is needed and make a choice there and leaving the default behavior for the rest of the components to be server-side rendered. So there are two main advantages to choosing the client component over the default serving component. One of them is the interactivity. So remember that as we've been seeing so far client components have access to state, to side effects, to event listeners, to browser APIs, to a lot of power that server components simply don't have access to. That gives you the extra ability to create very rich and interactive experiences through client components. Again, let's not abuse and just simply put everything on the client components. Remember that there is a reason why the default behavior is to be rendered on the server side. So keep that in mind whenever you are architecting your page and whenever you are thinking about a new section for your web app or a new section for your website, ask yourself the question, should this component be interactive?

    [02:05 - 03:46] And if the answer is yes then definitely and if the answer is no or perhaps maybe then you have to rethink your architecture. Again, the other extra benefit of these type of components is the access to the browser API. I already mentioned it before, it's a benefit for the interactivity aspect of it but this is not just about being interactive. These APIs will give you access to a lot of functionality that is simply not available on the server side. So it's also about pushing the boundaries of what a web application can do and that can only be achieved through client components. As we've seen in previous videos, these advantages are the main reason why you would choose client site rendering over server side rendering for your component. So now that we understand kind of the main benefits of client components, let's quickly review the reasons why you would go with the client component. It's always going back to the concept of page architecture. Any time you want an interactive UI element that can change based on user actions such as dynamic forms, animations or even real-time data display, these situations call for a like a speed and fluidity and that cannot be achieved through client components. Now keep in mind that when we're talking about data display, I'm saying display and not data gathering. Showing dynamic representations of your data is definitely a great use case for client components. But getting the data to work with and to showcase on screen can be an expensive action if you don't do it right.

    [03:47 - 04:21] When I say expensive, I mean that from a latency point of view, remember that here when we're talking about rendering a web page or a web app or specifically even showing data within a user flow, every micro second counts into either making it a great user experience or simply destroying the user experience by taking too long to render data or to show some kind of interactivity or feedback to the user. So when we're talking about expensive actions here, we're talking about that.

    [04:22 - 06:12] Making sure that we are smart about the way we gather data is also something that is related to page architecture and should also be considered whenever you are decided whether to create a client or server components for this. Again, the display side of dealing with data is definitely a great use case for client components. But getting that data from the client component would imply around trip to a local or potential external API. If it's local, it's probably getting that data from another source, probably like a database. And all that round trip is simply adding microseconds in the best case to the user experience. So instead, the data gathering data fetching is definitely something you should consider to put on the server side, which we'll get to in future videos. But right now, remember that when we're talking about data, there's a difference between displaying data and fetching the data. This playing is a great use case for client components, fetching it not so much. Again, you can definitely do it. It's just going to require more code and it's just going to require more time also. All right, so before we close this lesson, I want to show you another example of what an ideal client component looks like based on the use case. Here, I'm going to use the sample application that we're dealing with. And I'm going to show you the code for these buttons, the close and the remove buttons, which are essentially the same button simply with different initialization props. They take care of either removing one of these tasks from the list or marking them or rather updating their status to being done. We already saw that behavior before.

    [06:13 - 07:17] You can see here how they work. But I want to show you because this is a clear from the point of view of page architecture. We're talking about an atomic component that is meant to be causing a reaction on the rest of the application and is meant to be interactive with the user. So that from, again, from a page architecture point of view, it's the ideal use case for what we know as a client component. So let me show you the code. Now, here on the code, you see that from the definition point of view, like we've seen already, the only thing that stands out from previous versions of React or Next is the use of the directive use client at the top. And then this component is simply a wrapper around a button like we can see here at the bottom. The HTML returned by this component is just the HTML for a button. There is nothing else around it.

    [07:18 - 10:26] So again, this is what I mean when I say this is an atomic component. It is very minimal in the sense of how much HTML it is generating. So there is really no way for us to strip down anything from it and even and make it even smaller. So that's what I mean by atomic. In this particular case, our the focus or the bulk of the code that we're going to be writing for this component is on the behavior of what happens, essentially, when we click on it as a user. So again, this component receives two props, the task associated to the to the button to the action and the actual action, essentially, that is going to receive. And we know that whenever we click on this button, we're going to be calling the handle action function. This is the handler. This is this again, this is happening because our component is a client component and it has access to the DOM API. And thus, it has access to all the event handlers. It also is able to update its label based on the action that it receives. So these are very basic functions, but that determine whether the button is doing one thing or the other one clicked. And the actual action, essentially, that takes place whenever you click it, it's also defined by the action it received as a prop. And then it interacts with the task context that we've declared and that it provides two main functions, which are "mark as done" or "remove task". These are the ones that we want to interact with. And it also keeps a single stay variable to keep track of what text should show inside the button. And see here, it's either showing finished or closed or closed depending on whether it's meant to be closing or, you know, closing the task or saying that the task has been finished already. Again, this is happening because if we remember how state works, whenever we click on the button, if the action is mark as done, it will also set the internal state of the component to true. So there's going to be a change on the local state of the component. And as we know, whenever that happens, React will schedule a rerender. And when the rerender happens, this function is going to be called again, the displayButtonText function is going to be run again, because the whole component is going to be rerender. And when that happens, here, we will have a new value of the taskDone local state variable. And when that happens, it will decide whether to show one or the other values essentially. So again, this is a very slim client component. It's very, it's one of the best use cases for such a component. And again, the component itself is as small as it could be.

    [10:27 - 10:37] And that is what you should aim for whenever you're building your client components. From the page architecture point of view, you want your client components to be as slim as possible.

    [10:38 - 11:28] I'm not talking about the amount of JavaScript logic or business logic that it should have to achieve whatever interactivity or whatever you want to achieve. But from the markup content that returns, that's what I mean. Because here, so if the markup that you're returning is required to achieve the visual representation of your component, that's fine. That's not an issue. But if you're returning extra markup that is not really needed by the component, either for a visual representation or for functioning, getting data or showing data, then that markup is really not needed by the component, it should be somewhere else, potentially being statically rendered on the server side. So again, I want you to go back to the page architecture video.

    [11:29 - 12:01] If you don't remember exactly what was covered there and watch it again. With a new context that you have, it should make a lot more sense now than it did before. So deciding whether a component should be a server component or a client component will really determine the performance of your application as well as the maintainability of the code and even the scalability of your application. So this should not be a decision that gets made lightly. Instead, keep what we covered here in mind and remember try to make your client components as slim as possible by constantly asking yourself.

    [12:02 - 13:26] Does it really help my logic or the visualization of my component or can I render it statically somewhere else on a server component or somewhere that I don't care enough because I'm focusing on this particular component. Remember here we're fighting against performance both on the speed of execution but also on the speed of transfer. In some situations where you're using a top model computer with a high speed internet connection, this will definitely feel like a trivial problem, something you don't have to worry about. But you also have to remember users that are on 3g-networks or even with a limited bandwidth because of whatever reasons. It doesn't matter how many bytes you add. In the end, it will add up to a poor user experience. The more they have to download, it will be slower for them and it will be costly also for them. Potentially remember that some networks also tend to charge for data transfer. So the more attention that you pay here will pay off in the future. It turns into an overall better user experience. So everything counts, that's what I'm trying to get at. And to wrap it up, choose client components for parts of your application that demand interactivity everywhere else, server components and that's what we're going to cover on the next module. So see you there.