Back

Errores Comunes de JSX y Cómo Evitarlos

Errores Comunes de JSX y Cómo Evitarlos

JSX parece engañosamente simple—es solo HTML en JavaScript, ¿verdad? Sin embargo, incluso desarrolladores experimentados tropiezan con sus peculiaridades, especialmente a medida que React evoluciona. Con el runtime automático de JSX de React 19, los Server Components y el panorama cambiante de los frameworks modernos, estos errores tienen nuevas implicaciones. Aquí está lo que sigue causando problemas a los desarrolladores y cómo evitar estas trampas.

Puntos Clave

  • Los índices de arrays como keys causan problemas de reconciliación y rompen las características concurrentes de React
  • Los Server Components requieren patrones diferentes a los componentes cliente, especialmente en torno a las APIs del navegador
  • El runtime automático de JSX cambia cómo se transforma tu código y requiere una configuración adecuada
  • Las funciones inline y los patrones de renderizado condicional pueden degradar silenciosamente el rendimiento

La Evolución de JSX: Por Qué los Viejos Hábitos Rompen el Código Nuevo

El runtime automático de JSX introducido en React 17 eliminó la necesidad de importar React en cada archivo, pero también creó nueva confusión. Tu JSX ahora se transforma de manera diferente—las funciones jsx reemplazan a React.createElement, y las herramientas de compilación mal configuradas pueden romper silenciosamente tu aplicación.

En los Server Components, las apuestas son más altas. JSX que funciona perfectamente del lado del cliente falla cuando intenta acceder a window o usa hooks en el contexto incorrecto. Las reglas no solo han cambiado; se han multiplicado.

Trampas Críticas de JSX en React Moderno

1. Keys Inestables Que Destruyen el Rendimiento

// ❌ Índice como key - causa problemas de reconciliación
items.map((item, index) => <Item key={index} {...item} />)

// ✅ Identificador estable y único
items.map(item => <Item key={item.id} {...item} />)

Usar índices de arrays como keys sigue siendo uno de los errores de JSX más perjudiciales. En las características concurrentes de React, las keys inestables no solo causan parpadeos—pueden romper los límites de Suspense y desencadenar re-renderizados innecesarios en todo tu árbol de componentes.

2. Renderizado Directo de Objetos

// ❌ Los objetos no son hijos válidos de React
const user = { name: 'Alice', age: 30 };
return <div>{user}</div>;

// ✅ Renderizar propiedades específicas
return <div>{user.name}</div>;

Este mensaje de error no ha cambiado desde React 15, sin embargo, los desarrolladores aún intentan renderizar objetos directamente. Con la inferencia JSX de TypeScript, detectarás esto en tiempo de compilación—si tu tsconfig.json está configurado correctamente.

3. Funciones Inline Creando Nuevas Referencias

// ❌ Nueva función en cada renderizado
<Button onClick={() => handleClick(id)} />

// ✅ Referencia estable con useCallback
const handleButtonClick = useCallback(() => handleClick(id), [id]);
<Button onClick={handleButtonClick} />

En el pipeline de renderizado de React, las funciones inline no solo causan problemas de rendimiento—rompen la optimización de memo y pueden desencadenar actualizaciones en cascada a lo largo de tu árbol de componentes.

Server Components: Donde las Reglas de JSX Cambian

4. Código Solo-Cliente en Server Components

// ❌ Falla en Server Components
export default function ServerComponent() {
  const width = window.innerWidth; // ReferenceError
  return <div style={{ width }} />;
}

// ✅ Usar directiva client o pasar desde cliente
'use client';
import { useState, useEffect } from 'react';

export default function ClientComponent() {
  const [width, setWidth] = useState(0);
  useEffect(() => {
    setWidth(window.innerWidth);
  }, []);
  return <div style={{ width }} />;
}

Los Server Components se ejecutan fuera del navegador donde las APIs del DOM no existen. Esto no es un problema de configuración—es arquitectónico.

5. Componentes Asíncronos Sin Suspense

// ❌ Promesa no manejada en Server Component
async function UserProfile({ id }) {
  const user = await fetchUser(id);
  return <div>{user.name}</div>;
}

// ✅ Envolver con límite de Suspense
<Suspense fallback={<Loading />}>
  <UserProfile id={userId} />
</Suspense>

Los React Server Components pueden ser asíncronos, pero sin límites de Suspense apropiados, bloquearán el renderizado o fallarán con errores crípticos.

Trampas de Configuración de JSX Moderno

6. Configuración del Runtime JSX Desajustada

// ❌ Transformación antigua en tsconfig.json
{
  "compilerOptions": {
    "jsx": "react"  // Requiere importaciones de React
  }
}

// ✅ Runtime automático para React 17+
{
  "compilerOptions": {
    "jsx": "react-jsx"  // No necesita importación de React
  }
}

El runtime automático de JSX no es solo una conveniencia—es requerido para un tamaño de bundle óptimo y compatibilidad con Server Components. Una mala configuración aquí causa fallos silenciosos que solo aparecen en producción.

7. Anti-Patrones de Renderizado Condicional

// ❌ Devuelve 0 en lugar de nada
{count && <Counter value={count} />}

// ✅ Conversión booleana explícita
{Boolean(count) && <Counter  value={count} />}

Cuando count es 0, JSX renderiza el número 0, no nada. Este error es particularmente visible en React Native donde los nodos de texto requieren contenedores apropiados.

Estrategias de Prevención

Configura Tus Herramientas Correctamente: Configura ESLint con eslint-plugin-react y habilita estas reglas:

  • react/jsx-key
  • react/jsx-no-bind
  • react/display-name

Usa TypeScript: Con la configuración JSX adecuada, TypeScript detecta la mayoría de estos errores en tiempo de compilación. Habilita el modo strict y configura jsx correctamente en tu tsconfig.json.

Entiende Tu Runtime: Conoce si tu componente se ejecuta en el servidor o en el cliente. Next.js 14+ hace esto explícito con la directiva 'use client', pero el modelo mental aplica en todas partes.

Conclusión

Los errores de JSX en 2024 no son solo sobre sintaxis—son sobre entender dónde y cómo se ejecuta tu código. El runtime automático de JSX cambió el modelo de transformación. Los Server Components cambiaron el modelo de ejecución. Las características concurrentes de React cambiaron el modelo de rendimiento.

Domina estos fundamentos, y escribirás JSX que no solo es correcto, sino optimizado para las capacidades del React moderno. El mejor JSX es invisible—se quita del camino y deja que tus componentes brillen.

Preguntas Frecuentes

Cuando usas índices de arrays como keys, React no puede rastrear adecuadamente qué elementos han cambiado, se han movido o han sido eliminados. Esto obliga a React a re-renderizar más componentes de los necesarios y puede causar que el estado se asocie con el componente incorrecto después de reordenar.

Aunque las funciones inline funcionan correctamente, crean nuevas referencias en cada renderizado, rompiendo las optimizaciones de React.memo y potencialmente causando que los componentes hijos se re-rendericen innecesariamente. Para mejor mantenibilidad, usa useCallback para manejadores de eventos que dependen de props o state.

La configuración react usa la transformación clásica React.createElement que requiere importaciones de React en cada archivo. La configuración react-jsx usa el runtime automático introducido en React 17, que maneja la transformación sin importaciones explícitas de React y produce bundles más pequeños.

Gain Debugging Superpowers

Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers. Check our GitHub repo and join the thousands of developers in our community.

OpenReplay