Saltar al contenido principal

Cannot Read Properties of Undefined en React y Next.js: Solución Definitiva 2026

Soluciona TypeError: Cannot read properties of undefined (reading 'map', 'length', 'name'). Causas reales en React/Next.js, 3 soluciones con código y cómo evitarlo para siempre.

Fran Cobos 6 min de lectura 1068 palabras

Tabla de contenidos

🎯 Lo que aprenderás en este artículo

  • Por qué te pasa este error en React aunque el código parezca correcto (fetch, props, useEffect)
  • 3 soluciones con código copiable: optional chaining, guard clause y fallback seguro
  • Cómo evitarlo para siempre con TypeScript, Zod y tests

Es el error que más veces he visto en React, en DAW y en producción:

TypeError: Cannot read properties of undefined (reading 'map')

O su primo:

TypeError: Cannot read properties of undefined (reading 'length')
TypeError: Cannot read properties of undefined (reading 'name')

Traducción humana: intentas usar .map, .length o .name de algo que es undefined. React no puede renderizar undefined.map() y crashea toda la página en blanco.

La buena noticia: tiene 3 soluciones de 1 línea y se puede evitar para siempre con 2 hábitos.

Por qué te pasa (el 90% de los casos es uno de estos 3)

1. Los datos aún no han llegado

function UserList({ users }) {
  return <ul>{users.map(u => <li key={u.id}>{u.name}</li>)}</ul>
}
// Si users viene de un fetch, el primer render es users = undefined → CRASH

En Next.js App Router es aún más común con fetch en Server Component que tarda o falla.

2. No pasaste la prop o la escribiste mal

<UserList user={users} /> // singular
// dentro: users es undefined porque la prop se llama user

3. La API devolvió otra forma

Esperas { users: [...] } pero la API devolvió { data: [...] } o null por un error 500. Tu data.users.map crashea aunque el fetch sí hizo algo.

Si no sabes qué te devuelve la API, imprime antes de mapear: console.log(data). O pega el error en mi Traductor de Errores — te lo explica en español.

Solución 1: Optional chaining ?. (rápida, para salir del paso)

La más rápida. No crashea, simplemente no renderiza nada si es undefined.

// Antes (crash)
users.map(u => <li>{u.name}</li>)

// Después (seguro)
users?.map(u => <li key={u.id}>{u.name}</li>)

// Con fallback visible
users?.length ? users.map(u => <li key={u.id}>{u.name}</li>) : <p>Sin usuarios</p>

Cuándo usarla: componente pequeño, lista opcional, prototipo rápido.

Solución 2: Guard clause (la que yo uso en producción)

La más legible. Devuelves pronto si no hay datos.

function UserList({ users }: { users?: User[] }) {
  if (!users) return <p className="text-gray-500">Cargando usuarios...</p>
  if (users.length === 0) return <p>No hay usuarios aún.</p>

  return (
    <ul>
      {users.map(u => (
        <li key={u.id} className="py-1">{u.name}</li>
      ))}
    </ul>
  )
}

Ventaja: el usuario ve qué pasa (cargando / vacío) en vez de una página en blanco. En Next.js evita el Error Boundary rojo.

Solución 3: Fallback seguro con ?? + valor por defecto

Ideal cuando el dato viene de props o de un fetch que puede fallar.

// Componente siempre recibe array, nunca undefined
function UserList({ users = [] }: { users?: User[] }) {
  return <ul>{users.map(u => <li key={u.id}>{u.name}</li>)}</ul>
}

// Fetch con fallback
const res = await fetch('/api/users')
const data = await res.json()
const users: User[] = data.users ?? [] // si API falla, array vacío

Truco Next.js 15: si haces fetch en Server Component, valida con Zod para no fiarte de la forma:

import { z } from 'zod'

const UserSchema = z.object({ id: z.string(), name: z.string() })
const UsersResponse = z.object({ users: z.array(UserSchema) })

export default async function Page() {
  const res = await fetch('https://api.com/users', { cache: 'no-store' })
  const json = await res.json()
  const parsed = UsersResponse.safeParse(json)

  if (!parsed.success) {
    return <p>Error cargando usuarios.</p>
  }

  return <UserList users={parsed.data.users} />
}

Así TypeScript te obliga a manejar el caso undefined antes de llegar al .map.

Tabla: qué usar y cuándo

CasoSoluciónCódigo
Lista opcional, prototipo?.users?.map(...)
Página / componente críticoGuard clauseif (!users) return <Cargando/>
Prop que puede no venirDefault param({ users = [] })
Fetch a API externaZod + fallbackdata.users ?? []

Cómo evitarlo para siempre (2 hábitos)

Hábito 1: Tipa todo

// ❌ Mal: no sabes qué puede ser users
function UserList({ users }) { ... }

// ✅ Bien: TypeScript te avisa si puede ser undefined
type User = { id: string; name: string }
function UserList({ users }: { users: User[] | undefined }) { ... }

Si users puede ser undefined, el editor te subrayará users.map hasta que lo arregles.

Mi guía: TypeScript para JavaScript developers 2026.

Hábito 2: Valida lo que entra

No confíes en fetch. Valida:

// Antes: confías
const users = data.users // si API cambia, crash

// Después: validas
const users = z.array(UserSchema).parse(data.users) // si falla, error controlado

Más: Parsear JSON de IA sin errores y variables de entorno en Next.js.

Caso real: Next.js 15 + Prisma

Este es el caso que más veo en DAW (lista de usuarios desde base de datos):

// app/users/page.tsx — Server Component
import { prisma } from '@/lib/prisma'
import { UserList } from '@/components/UserList'

export default async function UsersPage() {
  const users = await prisma.user.findMany() // siempre es array, nunca undefined

  // Pero si filtras y puede venir null:
  const user = await prisma.user.findUnique({ where: { id } })
  // user puede ser null → no hagas user.name sin comprobar

  return <UserList users={users} />
}

// components/UserList.tsx — Client Component
'use client'
type User = { id: string; name: string }

export function UserList({ users }: { users: User[] }) {
  if (users.length === 0) return <p>Nadie por aquí aún.</p>
  return <ul>{users.map(u => <li key={u.id}>{u.name}</li>)}</ul>
}

Prisma siempre devuelve array, pero findUnique puede devolver null. Ahí es donde aparece el reading 'name'.

Checklist debugging (cuando no sabes de dónde viene)

  1. Mira la línea exacta del stacktrace: at UserList (src/components/UserList.jsx:12:24) → línea 12, columna 24
  2. Pon console.log(users) justo antes del .map y recarga
  3. Revisa el Network tab: ¿tu fetch devuelve 200 o 500? ¿Qué JSON trae?
  4. Si el error es intermitente, es 100% dato que a veces no llega → usa guard clause
  5. Pega el traceback en el Traductor de Errores para ver causa y fix paso a paso, o genera un prompt con el Generador de Prompts y que la IA te dé el parche

También: Errores comunes con Copilot y Cline en VS Code y la colección completa en /blog/errores/.


¿Te sigue saliendo? Pega tu error + el componente que falla en el Traductor de Errores y te digo la línea exacta que arreglar. Si quieres que lo mire con tu repo real, link en mi portfolio y lo vemos.

Fran Cobos

Fran Cobos

Desarrollador Full Stack especializado en IA aplicada, automatización y desarrollo web. Escribo sobre herramientas, tutoriales y casos reales para programadores.

¿Necesitas desarrollo a medida?

Apps web, IA, módulos ERP — cuéntame tu proyecto.