GOOHUB

Publicado por Diana Huaripayta G. el Aug 15, 2025

Diana Huaripayta G.

"use client" en Next.js: Guía clara para entenderlo y usarlo bien


En Next.js, desde la llegada del App Router (v13+), todo cambió en la forma en que pensamos sobre dónde se ejecuta nuestro código.

Antes, todo React se ejecutaba en el cliente (navegador) por defecto.

Ahora, en el mundo moderno de Next.js, los componentes se ejecutan en el servidor por defecto y el cliente es la excepción.

Next.js 12 y anteriores - TODO en cliente por defecto

function MyComponent() {
  const [count, setCount] = useState(0) // ✅ Funcionaba sin problemas
  return <div>Count: {count}</div>
}

Next.js 13+ App Router - Server Component por defecto

function MyComponent() {
  const [count, setCount] = useState(0) // ❌ Error! useState no existe en servidor
  return <div>Count: {count}</div>
}

Next.js 13+ - Declarando explícitamente como Client Component

"use client"

function MyComponent() {
  const [count, setCount] = useState(0) // ✅ Ahora sí funciona
  return <div>Count: {count}</div>
}

1. ¿Qué es "use client"?

"use client" es una directiva especial que le dice a Next.js:

“Este componente debe ejecutarse en el lado del cliente (navegador) y no en el servidor”.

Esto es necesario cuando tu componente necesita:

  • Interactividad (botones, formularios, sliders, etc.).
  • Hooks de React que dependen del navegador (useState, useEffect, useRef…).
  • APIs del navegador (localStorage, window, document…).
  • Librerías que solo funcionan en el cliente (por ejemplo, Framer Motion para animaciones).

Ejemplo:

"use client";

import { useState } from "react";

export default function Contador() {
  const [count, setCount] = useState(0);
  return (
    <button onClick={() => setCount(count + 1)}>
      Contador: {count}
    </button>
  );
}

La documentación de Next.js recomienda. 👀


You do not need to add the 'use client' directive to every file that contains Client Components. You only need to add it to the files whose components you want to render directly within Server Components. The 'use client' directive defines the client-server boundary, and the components exported from such a file serve as entry points to the client.

El Concepto de "Frontera" (Boundary) Aquí viene la parte crucial que muchos developers no entienden: Es decir , "use client" NO es heredable hacia arriba, solo hacia abajo Ejemplo:

// app/page.jsx - Server Component 📌
export default function HomePage() {
  return (
    <div>
      <h1>Bienvenid@ (renderizado en servidor)</h1>
      
      {/* ⬇️ AQUÍ SE CRUZA LA FRONTERA ⬇️ */}
      <InteractiveSection />
      
      <footer>Footer (renderizado en servidor)</footer>
    </div>
  )
}

👇

// components/InteractiveSection.jsx - PUNTO DE ENTRADA AL CLIENTE 📌
"use client"
import Button from './Button'
import Modal from './Modal'
import Counter from './Counter'

export default function InteractiveSection() {
  return (
    <div>
      <h2>Sección interactiva</h2>
      {/* ✅ Todos estos se ejecutan en cliente automáticamente */}
      <Button />
      <Modal />
      <Counter />
    </div>
  )
}

👇

// components/Button.jsx - SIN "use client" (hereda del padre) 📌
import { useState } from 'react'

export default function Button() {
  const [clicked, setClicked] = useState(false) // ✅ Funciona sin "use client"
  
  return (
    <button onClick={() => setClicked(!clicked)}>
      {clicked ? '¡Clickeado!' : 'Click me'}
    </button>
  )
}

Error Común: Poner "use client" en cada archivo

// ❌ MALO - Redundante e innecesario
"use client" // No necesario
function Button() {
  return <button>Click</button>
}

"use client" // No necesario  
function Modal() {
  return <div>Modal</div>
}

"use client" // Solo este es necesario
function InteractiveSection() {
  return (
    <div>
      <Button /> {/* Ya es cliente por herencia */}
      <Modal />  {/* Ya es cliente por herencia */}
    </div>
  )
}

¿Cuándo Usar "use client"?


✅ Cuándo SÍ usarlo:

1. Estados y Hooks de React

"use client"
import { useState, useEffect } from 'react'

function UserProfile() {
  const [user, setUser] = useState(null)
  
  useEffect(() => {
    // Lógica que requiere el navegador
    fetchUserProfile()
  }, [])
  
  return <div>Perfil: {user?.name}</div>
}

2. Event Handlers

"use client"
function ContactForm() {
  const handleSubmit = (e) => {
    e.preventDefault() // ❌ Sin "use client" esto falla
    console.log('Formulario enviado')
  }
  
  return (
    <form onSubmit={handleSubmit}>
      <button type="submit">Enviar</button>
    </form>
  )
}

3. APIs del Navegador

"use client"
function ThemeToggle() {
  const toggleTheme = () => {
    // ❌ `localStorage` no existe en el servidor
    const currentTheme = localStorage.getItem('theme')
    const newTheme = currentTheme === 'dark' ? 'light' : 'dark'
    localStorage.setItem('theme', newTheme)
  }
  
  return <button onClick={toggleTheme}>Cambiar Tema</button>
}

4. Librerías que Dependen del DOM

"use client"
import { useEffect } from 'react'
import { gsap } from 'gsap' // Librería de animación

function AnimatedComponent() {
  useEffect(() => {
    // ❌ GSAP necesita acceso al DOM
    gsap.from('.box', { duration: 2, x: -100 })
  }, [])
  
  return <div className="box">Animación</div>
}

✅ Cuándo NO usarlo:

1. Contenido Estático

// ✅ Perfecto como Server Component
function AboutPage() {
  return (
    <div>
      <h1>Acerca de Nosotros</h1>
      <p>Somos una empresa...</p>
    </div>
  )
}

2. Fetch de Datos

// ✅ Mejor en el servidor
async function BlogPosts() {
  const posts = await fetch('https://api.blog.com/posts')
  
  return (
    <div>
      {posts.map(post => (
        <article key={post.id}>
          <h2>{post.title}</h2>
          <p>{post.excerpt}</p>
        </article>
      ))}
    </div>
  )
}

Consejo estos 3 Pasos 👇



Paso 1: Identifica la Necesidad

¿Tu componente necesita alguno de estos?

  • useState, useEffect, hooks de React
  • Event handlers (onClick, onSubmit, etc.)
  • APIs del navegador (localStorage, window, document)
  • Librerías que solo funcionan en el cliente

Paso 2: Encuentra el Punto de Entrada

Busca el componente padre más alto que necesite ser cliente.


Paso 3: Declara la Frontera

Pon "use client" solo en ese componente padre.


Beneficios de Esta Estrategia


🚀 Mejor Rendimiento

  • Máximo contenido renderizado en servidor
  • JavaScript mínimo enviado al cliente
  • Tiempo de carga más rápido

🧹 Código Más Limpio

  • No repites "use client" innecesariamente
  • Estructura más clara y mantenible
  • Separación clara entre servidor y cliente

💡 SEO Mejorado

  • Contenido estático indexable inmediatamente
  • No depende de JavaScript para mostrar contenido

Conclusión

La directiva "use client" en Next.js 13+ representa un cambio fundamental en cómo pensamos sobre las aplicaciones React. La clave está en:

  1. Entender que Server Components son el nuevo predeterminado
  2. Usar "use client" solo cuando realmente necesites interactividad
  3. Declarar la frontera una sola vez en el punto de entrada más alto
  4. Dejar que los componentes hijos hereden automáticamente

Recuerda 🤓: menos "use client" significa mejor rendimiento y experiencia de usuario. Úsalo estratégicamente, no por defecto.