Current section: Client Components 27 exercises
lesson

Intro to Client Components

Loading lesson

Transcript

00:00 Now we're going to get into the thing that's the actual innovation behind react server components up to this point We actually haven't really done a whole lot of stuff that you couldn't just do with other frameworks or other existing Approaches to building web applications for the last couple decades

00:15 But client components are what make react server components really special and it is a little bit of a mind bend For a lot of people are like wait. Why is it this complicated, but I promise you it is awesome And once we're all finished it will enable us to do a lot of really cool things So to get us there

00:32 I think will actually help if I take you through my talk that I gave about react server components It's titled and now you understand react server components So let's talk about how to implement to use client This talk was actually a simple version of the workshop that we're going through right now

00:49 And so we're going to see a couple of familiar things for example the use case so We want to be able to edit the title of the ship and the way that that's going to work is you have a button that you render the title of ship inside and When you select the button it changes to an input and focuses the text and you can make a change

01:08 And then you hit enter to submit so there are a couple of things going on in here Now here is our ship details. This should look a little familiar. We've got a a sink component This is a server component. That's a waiting get ship and it renders the editable text This is the part that has some UI state in it. So if we look at the implementation there and then

01:28 You'll notice we've got this use state call for both the edit text the editable state and the value and then we also have some refs to keep Track and focus and do stuff like that. And then we also have Some event handlers and things like that going on in here, too

01:46 These are things that can't be serialized into the RSC payload. You can't serialize a function I know some of you are thinking yeah, but I know about you server Kent So you actually could serialize that action if you wanted to and yes, technically that will work and we'll learn a lot about that later But the on click you're not serializing that thing and so the

02:06 There are just some things that cannot be serialized into a string of text Like I guess we could just serialize the source code, but that's actually kind of what Server components does is it takes that source code sticks it over somewhere or your bundler will and then Tells the RSC payload where to go get that. I just barely thought about that

02:28 But yeah, that's sort of what's going on is we're serializing it just in a different way. So Besides the the functions it's also the state that needs to be addressed. We can't serialize something that's living in memory It would be like you might say well in server rendering

02:46 We just call this function with the the default values and and render everything as HTML Whatever and send it to the client and then we hydrate and go grab those same components and hydrate those And yeah that works, but it's because they're hydrated on the client now And so as the users making changes to the state and things it's all living right there

03:06 Whereas with the like a server component you can't take that state and if you wanted to revalidate the server component content or something like how would you tell the stateless server or The server over that stateless HTTP Protocol, how would you say?

03:25 Here is the current state of all my components. That would probably be really wasteful And it wouldn't quite make a lot of sense. Anyway, so we're not serializing the state That's a given it's a Taken for granted that we can't serialize state and functions in that RSC payload

03:42 So what do we do now? We can't have editable text. We represent it in the payload like that just doesn't work now what we do is We add this use client Directive to the top of our file and then we have some special magic that turns use client modules into something else So that we're not even trying to render this editable text and instead we just have

04:03 a little bit of code that Allows us to reference this in our RSC payload if you want a good metaphor for this Dan Abramov Refers to use client as a door and I'm not going to get into that right now because we're focused on the implementation

04:20 But that was a good talk at react conf 2024. So give that a watch so what this looks like in our payload is Now the client components are going to be serialized in this format And again, like the payload is an implementation detail this totally could change but this is the right mental model for you

04:40 We have to have a path to the module for actually loading the module for the browser And then the name of the export on that module that we're trying to represent here And so how do we take that module that is just like here's our component and all you know Whatever else we're exporting and get it into a state where we know the path of that module

05:00 We do this using a node loader And so here's the actual implementation that you're going to be building in this exercise I'm not going to go into this because that would be too much of a spoiler for you But we'll look at that a little bit here in a sec

05:15 The result though is that we're going to take the edit text module that appears like this and we're going to convert it at Runtime into this special type of Module, so there is a point between the time that your

05:33 Code is being imported and the point where it's actually evaluated and executed Where we can actually do some work so with a bundler you're actually you can read the files You can compile them and change their contents and all of that stuff like you can have Babel plugins that do all of that

05:50 But we're not using in any of those things so instead we're going to use a node loader It's a special hook that you can register with node and say hey node anytime you import a file Before you actually evaluate the contents of that file I want you to hand it to me, and I'm going to make some changes to it potentially

06:08 And so what our node loader is going to do is it will say hey if that file includes the text use client Then we're going to treat that as a client component We're going to take all of its exports and all even its imports will remove all the imports take all the exports and convert them into a Client reference, so we're going to register the client reference. This is going to accept a

06:28 Function that so this will be our proxy implementation That simply throws an error saying hey you tried to call the editable text function from the server But it's a client component, so you can't do that because we can't serialize it whatever you you there's something wrong You're doing something wrong, and then the second argument is

06:48 the path to that module so We know like how to resolve this module when we're resolving it in the client So this is the the file system path of course the the client doesn't want that file system path And if you remember earlier our RC content didn't have the file system path

07:05 So we'll be removing that shortly and then the last argument or to this register function is the Named export so the export that this export represents And if you console like the register client reference that turns into a function that has a couple extra properties

07:24 and these are the properties a type of to rip so that it actually is a React component this is how react identifies components is via this dollar dollar type of property And so this will be a react client reference And then an ID and this will have the full file path with a little hash sign

07:44 Hashtag pound sign whatever you call that and then the name of the export that this Function represents and so by that object So that's that's what's flying around on our server when we're importing it in server components and things Is a function with these properties and so by those properties the RSC?

08:05 Generating function are rendered a pipeable stream. We'll look at the component be like oh, you're a client reference, okay? So I'm not going to bother calling you and instead. I'm going to grab your ID and use that to generate this reference right here

08:19 Which I think is actually yeah, that's pretty pretty elegant pretty interesting and then on the client side we need to resolve Well first we need to get rid of the file colon slash slash and and then update our UI to be able to resolve That slash edit text which we'll look at right here After I talk about a couple of things here first

08:41 So the thing that you need to understand here is that server components cannot be imported in use client Modules and that's because the use client module is going to run on the browser and server components Are async components and they also have access to database and and process ENV and like whatever else and so you wouldn't want to

09:03 evaluate a server component module in a client module anyway, but yeah, it certainly wouldn't be possible and This is a limitation that a lot of people myself included were really frustrated by But it turns out that this actually encourages us to do something that I've been trying to get

09:19 React developers to do for years myself included and that is to write more composable UI And so what you do instead is if you need to have a some server UI that's inside of client UI is you use composition and we talked about this in the advanced react patterns workshop

09:39 Where we have a prop that represents our server UI and we can render it wherever we want to inside of our client component So if you've got a combo box and you have server component pieces in that combo box Yeah, you just have that combo box except children or something like that and it can Render those server components and so we have this really nice composable

09:59 Story here, which I think is is pretty great. So let's do a little bit more exploring of the RSC syntax. So once you're finished, we'll have a couple of these client component references Once we're totally finished like in the next exercise, you'll notice the RSC payload has a couple more client references

10:20 once we support client components and if we take a look at just the ship search Here, then you'll notice this is to colon. I okay So now we come down here and we'll find dollar l2

10:35 so this I'm not sure what the the letters signify it is seems like random to me, but if we understand the the structure of our application then we'll know okay, so this is the thing that has a class name search and Its children includes this dollar l2

10:55 That is definitely our ship search component. And so that's how that reference works there again This is an implementation detail of how all this stuff works. So it's not necessarily going to be this way forever If I don't see any reason why it would change

11:10 But it definitely could and the most important part here is that you understand that when we're serializing client components We serialize them by having a reference to the module that contains the code and the name Export from that module and then we deserialize it by loading that and then evaluating it on the client

11:29 The other thing to keep in mind is we're doing a single page app here so there's no server rendering, but you could add server rendering to this as a Optimization and then the server We have the RSC server over here But then we have our our server rendering process as well. And so that thing needs to

11:49 Evaluate all this stuff too. So you can think of the server rendering server as another client of the RSC server And so it will actually Resolve these modules and it and evaluate them and server render them as well So you can totally do both but we're just doing the UI or the browser only

12:08 Okay, great. So how does the browser resolve this stuff? well first we don't want to send the file colon slash slash to the client that doesn't make any sense and so We're going to give a module base path to render to pipeable stream again. This one comes from react server DOM ESM So it's a slightly different API from other rendered or pipeable streams you've seen before

12:28 But the second argument for this one is the module base path And so this is just going to be the file URL for where our UI components live So we can chop off the extra information. That's not necessary on the client So this will basically be the file colon slash slash all the way to our UI directory

12:48 It'll chop everything off and that's why we end up with slash edit text dot JS and then on the UI side of things in Create from fetch it accepts a module base URL And so this is just like hey tack this on to the beginning of our edit text And this is how you resolve that particular module. So our server has been set up to serve all the UI

13:09 Files all the files in the UI directory and so we say hey This is where you go get that the server will send you that module and that's how we resolve that so we're going to be doing both of these steps creating the node loader so that we can transform the component code that client module into one that just registers a bunch of exports and then

13:30 Updating our server and client to be able to resolve the where those modules actually reside Okay, great. I think I've talked plenty you can feel free to dive into the example from The react docs this how client use client marks client code is kind of interesting

13:48 Especially talking about composability of this client component with the server component stuff like that So feel free to dive into that and if you want to understand node loaders more You'll want to take a look at customization hooks in the node docs But yeah, you should be guided pretty well because this isn't a node workshop So I'm going to be guiding you quite a bit on that And by the end of it

14:09 You should be able to look at the RC content and see this server references and stuff like that or the client references Which is pretty cool. So Let's get into this exercise