Client or Server component ?
Tags: nextjs, component, typescript, webdev
Published: 2023-12-30 09:31:38

Recently, I had a project that needed to be rewritten from React to Next.js. I worked with individuals who weren't familiar with server components and how they work, so they kept asking me constantly:

> 💬 How do i know if this component is a server one or a client one?

My first answer (a silly one you may say 😕) was: 
> 💬 Just check at the top of the file if it contains 'use client' or not" 😇

Just for those who didn't made the jump to NextJS yet, all components in NextJS are server by default so if you needed a client one, you have to add *"use client"* at the top of your file.

Later, they came to me again with another question:
> Ok, we got it, when there is *"use client"* at the top, it is a client one but how comes this other component that doesn't have *"use client"* inside it claims to be one?

I was suggested to rename every server file into something explicit like `ServerTagComponent` 🤧

But then i remembered a video of [Jack Herrington about state management in Next.JS](https://www.youtube.com/watch?v=OpMAH2hzKi8) with this kind of segmentation in his components:

![segmented_component](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/300fzgn99z61c54n1f7j.png)

Wouldn't it be cool to have something like this in your components 🤩?

So the general idea is to implement a [higher order components](https://legacy.reactjs.org/docs/higher-order-components.html) that adds a label for each component that uses it. 

The final result should be something like this:

![expected_result](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fj046i1juzn8n0lnj8n8.png)

And every component that needs it should have a `withComponentIdentifier` in order to display these boxes.

## Our HOC component
A Higher Order Component (HOC) is a function in React that takes a component and returns a new component with additional features or behaviors. 

It's a way to reuse component logic and share functionalities among different parts of your application.

Let's start by creating our HOC file:
```js
// components/ComponentIdentifier
import { ComponentType, FC } from 'react';

export function withComponentIdentifier<P extends object>(
  WrappedComponent: ComponentType<P>
): ComponentType<P> {
  const WithComponentIdentifier: FC<P> = (props) => {
    const isClient = typeof window !== 'undefined';
    const display = isClient ? 'client' : 'server';
    return (
      <div>
        <p className={`hoc-text ${display}`}>This is a {display} component</p>
        <div className='hoc-content'>
          <WrappedComponent {...props} />
        </div>
      </div>
    );
  };

  return WithComponentIdentifier;
}
```
This is a simple HOC component written in TypeScript, but the trick here is on this line:
```js
  const isClient = typeof window !== 'undefined';
```
Because a server component is rendered by the server then it shouldn't have a window property. 

## Usage
Now that we have our HOC component, let's use it. Create any tsx file that you want inside our `app` folder. I chose to name mine `client.tsx` then create a simple client component:
```js
// app/client.tsx
'use client';

const ClientComponent = () => {
  return <p>This is a simple client component</p>;
};

export default ClientComponent;
```

Then create another component called `server.tsx`:
```js
const ServerComponent = () => {
  return <p>This is a server component</p>;
};

export default ServerComponent;
```

Finally, create a component that we will identify:
```js
// app/unknown.tsx
const UnknownComponent = () => {
  return <p>This is an unknown component</p>;
};

export default UnknownComponent;
``` 
We will use this component inside each file created previously to determine either it's a client or a server component.

Your final `page.tsx` should be like this:
```js
import ClientComponent from './client';
import ServerComponent from './server';

export default async function HomePage() {
  return (
    <>
      <ClientComponent />
      <ServerComponent />
    </>
  );
}
```

![client_server_result](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l18lwt62ackaqqbphgw0.png)

Now, let's use our HOC inside these components:
```js
// app/client.tsx
'use client';

import { withComponentIdentifier } from '@/components/ClientOrServer';

const ClientComponent = () => {
  return <p>This is a simple client component</p>;
};

export default withComponentIdentifier(ClientComponent);
```

And the `server.tsx`:
```js
import { withComponentIdentifier } from '@/components/ClientOrServer';

const ServerComponent = () => {
  return <p>This is a server component</p>;
};

export default withComponentIdentifier(ServerComponent);
```
Just like that, we now have these cool boxes:

![boxes_result](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/61ctdtpfiv5gonjsb4sl.png)

## Use case
Although these components are clearly explicit, there is a scenario where you might not know if a component is nested inside a client or server component. This is where our Higher Order Component (HOC) proves to be truly useful. Let's consider a situation where we call our UnknownComponent within our ClientComponent (and remember to include our HOC in our UnknownComponent).

```js
// app/client.tsx
'use client';
import UnknownComponent from './unknown';

const ClientComponent = () => {
  return (
    <>
      <p>This is a simple client component</p>
      <UnknownComponent />
    </>
  );
};

export default ClientComponent;
```
Notice that i removed the HOC from the ClientComponent resulting to identify just the unknown component.

![unknown_component](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kcf7m023h28bdwd6gayj.png)

Now, let's just move our `UnknownComponent` inside our `ServerComponent`:
```js
// app/server.tsx
import UnknownComponent from './unknown';

const ServerComponent = () => {
  return (
    <>
      <p>This is a server component</p>
      <UnknownComponent />
    </>
  );
};

export default ServerComponent;
```
Here is the result:

![final_result](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tdlltr4cb5b1hs1q8mn4.png)

## Conclusion
With the usage of that HOC, everyone can now wrap components to determine if its a client one or a server one without asking all the time! 😄😇

Thanks for reading!

<a href="https://www.buymeacoffee.com/ailifidaach" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" style="height: 60px !important;width: 217px !important;" ></a>