3 things you should care about Client Component 【Next.js app/】
Tags: nextjs, react
Published: 2023-10-25 11:44:48

## 1 - How to use 'use client'

There are two ways to make a component client-side.

### No.1: Add `'use client'` at the beginning of the file

By adding `'use client'` at the beginning of the file, it becomes a Client Component. I think this is the most basic configuration method.

```tsx
// app/ClientComponent.tsx
'use client'

export default function ClientComponent(){
    return (
        <button onClick={()=>{
            console.log('Hello, Client')
        }}>BUTTON</button>
    )
}

// app/page.tsx
import ClientComponent from './ClientComponent.tsx'

export default function Page(){
    return(
        <div>
            <ClientComponent />
        </div>
    )
}
```

### No.2: Pass through the file with 'use client'

Even if the component file itself does not have `'use client'`, you can make it a Client Component by importing it into another file with `'use client'`.

```tsx
// app/ClientComponent.tsx
export default function ClientComponent(){
    return (
        <button onClick={()=>{
            console.log('Hello, Client')
        }}>BUTTON</button>
    )
}

// app/client.ts
'use client'
export { default } from './ClientComponent.tsx'


// app/page.tsx
import ClientComponent from './client.ts'

export default function Page(){
    return(
        <div>
            <ClientComponent />
        </div>
    )
}
```

Thanks to this specification, even if an external library component does not support Client Component, you can treat it as a Client Component by adding `'use client'` to an arbitrary file and importing/exporting it.

However, please note that I explain more in the following section.

## 2 - Do not directly nest Server Components

If you import Server Component directly into the file of a Client Component and nest it, the Server Component will be treated as a Client Component (due to the specification shown in No.2 earlier).

To prevent this, set {children} on the Client Component side and wrap it with the opening tag of the Client Component.

```tsx
// ❌

// app/ServerComponent.tsx
export default function ServerComponent(){
    return(
        <div>Hello, Server</div>
    )
}

// app/ClientComponent.tsx
'use client'
import ServerComponent from './ServerComponent.tsx'

export default function ClientComponent(){
    return (
        <button onClick={()=>{console.log("Hello, Client")}}>
            <ServerComponent />
        </button>
    )
}

// app/page.tsx
import ClientComponent from './ClientComponent.tsx'

export default function Page(){
    return(
        <div>
            <ClientComponent />
        </div>
    )
}
```

```tsx
// ⭕️

// app/ServerComponent.tsx
export default function ServerComponent(){
    return(
        <div>Hello, Server</div>
    )
}

// app/ClientComponent.tsx
'use client'

export default function ClientComponent(){
    return (
        <button onClick={()=>{console.log("Hello, Client")}}>
            { children }
        </button>
    )
}

// app/page.tsx
import ClientComponent from './ClientComponent.tsx'
import ServerComponent from './ServerComponent.tsx'

export default function Page(){
    return(
        <div>
            <ClientComponent>
                <ServerComponent />
            </ClientComponent>
        </div>
    )
}
```

It is not necessary to always wrap it with the opening tag. However, you don't want to bring what can be generated on the server side to the client side, right?

## ~~3 - Do not import modules from index files (cannot)~~

---
**CAUTION**

This section was incorrect.

[See the revised version](https://dev.to/adamof/how-to-fix-module-not-found-cant-resolve-fs--44f4)

---

~~You cannot import from an `index.ts/js` file into a Client Component.~~

```tsx
// CAN NOT DO THIS

// lib/index.ts
export const sayHello = () => {console.log('Hello')

// app/ClientComponent.tsx
'use client'
import { sayHello } from '../lib'

export default function ClientComponent(){
    return (
        <button onClick={()=>{
            sayHello()
        }}>
            You can't do this with ERROR
        </button>
    )
}

```

If you try to do this, you will get the following error.

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/552712/192597de-e2f7-e213-5e77-032fffff8d3d.png)

## 4 - Pre-Rendering

Client components are first rendered on the server side.

[The official documentation mentions the following.](https://nextjs.org/docs/app/building-your-application/rendering/client-components)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/552712/f9cca7df-22a5-87ed-32f3-9b2d7a75654a.png)

For example, let's say you accidentally use a function inside the component that relies on the `document` object.

```tsx

// getDataTheme.ts
export const getDataTheme = () =>
  document.documentElement.getAttribute('data-theme')

// Button.tsx
'use client'
import {getDataTheme} from './getDataTheme'

export default function Button(){
    return (
        <div>{getDataTheme()==='dark'?'Moon':'Sun'}</div>
    )
}
```

In this case, you will likely see the following warning:

`ReferenceError: document is not defined`

This is likely caused by using a client-side API on the server side. Find a way to avoid this issue.

---

I have summarized the knowledge when creating Client Components. I hope it will be helpful to you.

That's all.