Anidar y componer control flow con For
El control de flujo de Solid compone: Show dentro de Switch, Switch dentro de For, Show envolviendo un For para el estado vacio. Cada nodo posee su subarbol y la destruccion cae en cascada. Patrones y heuristicas de legibilidad.
Anidar es componer ámbitos
Cada componente de control de flujo abre un ámbito reactivo —un owner— que posee lo que hay dentro. Anidarlos crea una jerarquía de propiedad: el nodo externo decide si existe el interno, y el interno solo cobra vida cuando su rama está activa. Esto no es solo estético; es gestión de recursos gratuita:
<Switch fallback={<NoAutorizado />}> <Match when={sesion()}> <Show when={sesion()!.esAdmin} fallback={<PanelUsuario />}> <PanelAdmin /> </Show> </Match></Switch>El Show interno no existe hasta que el Match de sesion() gana. Sus efectos no corren, su DOM no se crea, nada de su interior consume recursos mientras no haya sesión. Cuando sesion() pasa a nulo, el Match se desmonta y arrastra consigo al Show y a todo lo que colgaba de él. No escribes una sola comprobación defensiva: la jerarquía de ámbitos la hace por ti.
For + Show: estado vacío y condicional por elemento
For es control de flujo tanto como Show: recorrer una colección es ramificar sobre “cuántos y cuáles”. Se combinan en dos patrones canónicos que conviene tener en los dedos. El primero, el estado vacío: envuelve el For en un Show cuyo when es la longitud y cuyo fallback es el mensaje de lista vacía:
import { For, Show } from "solid-js";<Show when={pedidos().length} fallback={<p>Sin pedidos todavia</p>}> <ul> <For each={pedidos()}> {(pedido) => <li>{pedido.titulo}</li>} </For> </ul></Show>Gracias a la coerción de Show, pedidos().length igual a 0 activa el fallback sin fugas de 0 al DOM —justo la trampa de la lección anterior—. El segundo patrón, el condicional por elemento: un Show o un Switch dentro del hijo-función del For, de modo que cada fila decide su propia forma:
<For each={pedidos()}> {(pedido) => ( <li> {pedido.titulo} <Show when={pedido.urgente}> <span class="urgente">prioritario</span> </Show> </li> )}</For>Como For reconcilia por referencia del elemento, cada fila tiene su propio ámbito estable; el Show de dentro vive y muere con esa fila concreta. Reordenar la lista mueve los nodos ya creados sin recrear los Show internos, y eliminar un pedido limpia su fila entera en cascada. Si el estado por posición importara más que la identidad —campos de formulario, por ejemplo—, Index en lugar de For daría a cada posición un ámbito fijo con el elemento como señal.
Las tres piezas encajan en una sola composición legible: estado vacío por fuera, iteración en medio, rama por fila dentro.
<Show when={pedidos().length} fallback={<Vacio />}> <ul> <For each={pedidos()}> {(pedido) => ( <li> <Switch fallback={<span>estado desconocido</span>}> <Match when={pedido.estado === "enviado"}><Enviado /></Match> <Match when={pedido.estado === "pendiente"}><Pendiente /></Match> </Switch> </li> )} </For> </ul></Show>Léelo de fuera adentro y aparece el enunciado del problema tal cual: “si hay pedidos, por cada pedido, según su estado”. La forma del JSX es la forma de la frase, y esa coincidencia es la que hace mantenible el anidamiento.
Legibilidad: aplanar, extraer, nombrar
El control de flujo anidado degenera en pirámide con facilidad. Tres heurísticas lo evitan:
La meta no es minimizar líneas, sino que la estructura del JSX refleje la estructura del problema: una lista con estado vacío se lee como un Show sobre un For; una máquina de estados se lee como un Switch de estados nombrados; una fila con adornos condicionales se lee como un For con Show internos. Cuando la forma coincide, el anidamiento deja de pesar porque cada nivel dice una cosa y solo una.
La extracción a componentes es la palanca más potente. Compara una rama gorda inline con su versión con nombre:
// antes: la rama entierra la estructura del Switch bajo detalle visual<Switch> <Match when={estado() === "error"}> <div class="error"><Icono /><p>{mensaje()}</p><button>reintentar</button></div> </Match></Switch>// despues: el Switch se lee como un indice de estados nombrados<Switch> <Match when={estado() === "error"}><VistaError mensaje={mensaje()} /></Match></Switch>El Switch de la derecha se abarca de un vistazo: es un mapa de estados, no una maraña de div. Y VistaError se prueba y se reutiliza por su cuenta. La regla: el control de flujo debe mostrar qué ramas hay; el detalle de cómo se ve cada una vive en el componente de la rama.