Next: Client and Server Side Components
I’ve been doing more digging recently into Next.js since it’s such a powerful technology to use for fullstack development. I previously used it for its folder-based routing system, which I really enjoy. It makes the file and folder structure very intuitive.
I realized recently that although I have used server-side rendering, I didn’t have a strong grasp on client and server-side components. What tends to happen is if you use a hook on a server-side component, you’ll get an error. Something along the lines of “useState only works in Client Components.” Once you add ‘use client’ to the top of your file, you may run into another error. Something like ‘module not found.’
After some digging, I found that client components can’t render server components. That’s to say if your App file has ‘use client’ at the top, you can’t render a server component. The reason for that is because server components aren’t supposed to re-render, essentially making them almost immutable.
So what’s the fix? Well, you can flip the order such that the parent is a server-side rendered component and the child is a client-side component, but the side effect of that is you’d have to move all the state in the child to the parent. Obviously not a great choice if you wanted to encapsulate some logic to a specific component.
Let’s take a look at another approach. The rule is that a server component cannot be owned by a client component. If that doesn’t make sense — check out the code below that I found on Stack Overflow that explains the owner/ownee and parent/child relationship.
let A = () => {
return (
<B>
<C />
</B>
);
};
In the above example, A is the owner of B and C because A creates both of the components. However, B is the parent of C because C is passed as a child to B.
Using the code above, let’s consider that A is a client-side component. C is a server-side component. Let’s also take away B from the equation. A (client-side component) would own C (server-side component).
Let’s look at how B can help us in this case. So what is B doing here? Does B not own C? It doesn’t. Look at the below code to understand why B doesn’t own C in this case.
let B = ({children}) => {
return <div>{children}</div>
}
B doesn’t create C at all. With this approach, you can encapsulate some logic inside of B now and your project won’t break. This took me a while to understand, so if you have to review this a few times — that’s okay. I’d even urge you to do some research on this topic if you’re stuck!
As always, happy coding!