Saltar al contenido

Listas y renderizado condicional

Renderizar colecciones mapeando arrays a marcado con .map, el papel real de las keys en un framework que no reconcilia, y el renderizado condicional con el operador logico y el ternario, con la trampa de los valores falsy.

Listas con .map

Para renderizar una colección, mapeas el array a un array de nodos de plantilla. Astro renderiza un array concatenando sus elementos en su lugar, así que la llave contiene una sola expresión —la llamada a .map— que devuelve tantos elementos como datos haya.

ASTRO
---const lenguajes = ['Rust', 'TypeScript', 'Go'];---<ul>  {lenguajes.map((lang) => <li>{lang}</li>)}</ul>

Al ser JavaScript puro, encadenas lo que necesites antes de pintar: filtras, ordenas o accedes a campos de objetos dentro del propio .map. La plantilla se lee mejor cuando la transformación pesada vive arriba: calcula la lista final en el frontmatter y deja en la plantilla solo el .map que la proyecta.

Merece la pena saber qué hace Astro con cada tipo de valor, porque .map produce justamente un array. Un array se concatena elemento a elemento; los arrays anidados se aplanan; los false, null y undefined que aparezcan dentro se omiten sin ruido. Eso te permite mezclar en una misma estructura elementos y condiciones y confiar en que las ramas falsas simplemente no pinten, sin romper la concatenación del resto.

ASTRO
---const mostrarBanner = false;const filas = ['a', 'b'];---<section>  {[    <h2>Panel</h2>,    mostrarBanner && <p class="banner">Aviso</p>,    ...filas.map((f) => <div>{f}</div>),  ]}</section>

En ese array conviven un elemento fijo, una condición con && y una lista expandida con el operador de propagación. Astro los aplana y concatena; la rama mostrarBanner && ..., al ser falsa, se evapora sin dejar hueco. Es la prueba de que renderizar listas y renderizar condiciones son, por debajo, el mismo gesto: producir valores que Astro concatena.

ASTRO
---const posts = [  { titulo: 'Islas', min: 8 },  { titulo: 'Rutas', min: 12 },];---<ul>  {posts    .filter((p) => p.min < 10)    .map((p) => <li>{p.titulo} en {p.min} min</li>)}</ul>

Las keys: un artefacto que Astro no necesita

Quien viene de React esperará una key en cada elemento mapeado, y el aviso de consola cuando falta. En Astro no hay tal aviso, y no es un olvido. La key existe en React para la reconciliación: cuando el componente se re-renderiza, React compara el árbol viejo con el nuevo y usa la key como identidad para mover lo mínimo. Astro nunca reconcilia; renderiza la lista una vez, la emite como HTML y termina. Sin re-render no hay nada que reconciliar, y sin reconciliación la key no tiene trabajo que hacer.

Puedes escribir key si quieres —Astro no protesta—, pero en la salida estática es inerte: ni siquiera llega al HTML final. La única excepción vive dentro de una isla: si el elemento mapeado es un componente de un framework hidratado en el cliente, las reglas de ese framework aplican dentro de su isla. Pero eso es asunto de React o Svelte, no de la plantilla de Astro que los rodea.

Condicionales: el operador && y el ternario

Sin if dentro de la llave, los condicionales se expresan con operadores que devuelven un valor. El && sirve para mostrar u ocultar un bloque; el ternario, para elegir entre dos alternativas reales.

ASTRO
---const usuario = { nombre: 'Ada', admin: true };const avisos = [];---{usuario.admin && <a href="/panel">Panel de control</a>}<p>{usuario.nombre ? `Hola, ${usuario.nombre}` : 'Invitado'}</p>{avisos.length > 0  ? <span class="rojo">{avisos.length} avisos</span>  : <span class="verde">Todo en orden</span>}

El && aprovecha que false, null y undefined no pintan nada: si la condición es falsa, la expresión completa vale false y Astro no emite nada; si es verdadera, vale el elemento de la derecha y lo pinta. El ternario, en cambio, siempre elige una de sus dos ramas, así que encaja cuando de verdad hay una alternativa que mostrar en lugar de un simple aparecer-o-no.

Un aviso de estilo cierra el punto: anidar ternarios dentro de la plantilla —un ternario cuya rama es otro ternario— se vuelve ilegible enseguida. Cuando una decisión tiene más de dos ramas, la señal es clara: súbela al frontmatter, resuélvela allí con un if o un switch de verdad —que en la zona de sentencias sí caben— y deja en la plantilla una sola variable ya calculada. La plantilla gana cuando expresa qué se muestra, no el árbol de decisiones que llevó a ello.

La trampa del 0

Aquí reaparece la peculiaridad de la lección anterior, y merece una sección propia porque muerde a mucha gente. false, null y undefined se borran del HTML, pero el número 0 pinta su “0” como texto. Por eso una guarda como {avisos.length && ...} es una bomba silenciosa: si el array está vacío, length vale 0, la expresión entera vale 0, y Astro escribe un “0” suelto en la página en lugar de no escribir nada.

ASTRO
{/* trampa: pinta un 0 cuando la lista esta vacia */}{avisos.length && <ul>...</ul>}{/* correcto: la guarda es un booleano de verdad */}{avisos.length > 0 && <ul>...</ul>}

La solución es convertir la guarda en un booleano genuino —length > 0, Boolean(x), !!x— para que el lado izquierdo sea siempre true o false, nunca 0. Es exactamente el mismo desliz que en JSX y por la misma razón: el cero es un valor falsy pero visible. Interiorizar que estás manipulando los valores crudos de JavaScript, sin una capa que los interprete por ti, es la mejor vacuna contra este bug.