wandres.dev
CONTROL FLOW: SHOW Y SWITCH · condicionales reactivos

Show: when, fallback y keyed

Show es el condicional reactivo de Solid. Renderiza sus hijos cuando when es verdadero y el fallback cuando no, memoiza la coercion booleana para no recrear en vano y, con keyed, recrea el subarbol cuando cambia la identidad del valor.

⏱ 13 min

Show es el if de un lenguaje reactivo, pero reducirlo a “un ternario con mejor sintaxis” es perder lo esencial. Show hace tres cosas que un operador crudo no hace: memoiza la coerción booleana de when para no recrear a sus hijos cuando la condición cambia sin cambiar de verdad, ofrece una ranura fallback para el caso falso, y con el modificador keyed invierte su propia semántica para recrear el subárbol cuando cambia la identidad del valor. Entender esos tres comportamientos es entender el condicional de Solid.

🎯 Al terminar esta lección sabrás
  • Leer la firma de Show: la prop when, la prop fallback y los hijos.
  • Entender que Show memoiza la coerción booleana de when.
  • Distinguir cuándo Show conserva los hijos y cuándo los recrea.
  • Usar keyed para forzar la recreación al cambiar la identidad del valor.

La firma: when, fallback e hijos

Show recibe una prop when y unos hijos; renderiza los hijos cuando when es truthy y, si no, renderiza la prop fallback —que por defecto es nada—:

import { Show } from "solid-js";

function Panel(props: { cargando: boolean; datos: Datos }) {
  return (
    <Show when={!props.cargando} fallback={<Spinner />}>
      <Vista datos={props.datos} />
    </Show>
  );
}

when no exige un booleano estricto: cualquier valor truthy activa los hijos y cualquier valor falsyfalse, null, undefined, 0, "", NaN— activa el fallback. El tipo lo dice literalmente: when es T | undefined | null | false. Esa coerción es deliberada y es justo lo que convierte a Show en el guardián de nulos idóneo, tema que retomaremos en la última lección de este nivel. Como todo control de flujo de Solid, Show vive dentro del JSX: el compilador rastrea la lectura de when y reevalúa la rama cuando su valor cambia, sin volver a ejecutar el cuerpo del componente. Y fallback es tan reactivo como los hijos: puede ser un componente con su propio estado, no solo un texto muerto.

La condición se memoiza: por qué no recrea

Aquí está la propiedad que separa a Show de un &&. Internamente, Show envuelve when en un memo cuyo equals compara la verdad booleana, no el valor: en esencia (a, b) => !a === !b. Por eso el bloque de hijos solo se recalcula cuando when cruza la frontera falso↔verdadero. Mientras when siga siendo truthy, aunque su valor interno cambie de un truthy a otro, los hijos no se recrean:

const [texto, setTexto] = createSignal("hola");

// el Editor se crea UNA vez cuando texto() pasa a no-vacio,
// y conserva su estado interno al pasar de "hola" a "adios"
<Show when={texto()}>
  <Editor />
</Show>

La consecuencia es enorme y silenciosa: el estado interno del subárbol —el valor de un input, el foco, el scroll, un createEffect a medias— sobrevive a los cambios de when que no alteran su verdad. Compruébalo con un caso tangible: un campo no controlado dentro del Show mantiene lo que el usuario escribió aunque la condición pase de un truthy a otro truthy.

const [rol, setRol] = createSignal("editor");

// al cambiar rol de "editor" a "revisor", ambos truthy,
// el input NO se vacia: Show conserva el subarbol
<Show when={rol()}>
  <input placeholder="tu nota" />
</Show>

La documentación lo enuncia sin rodeos: sustituir un valor truthy por otro truthy no recrea el bloque hijo. Un ternario crudo no te ofrece esa garantía como capacidad nombrada; Show la hace explícita e incondicional.

flowchart TD
W[when cambia de valor] --> M[memo de la condicion equals por verdad]
M -->|misma verdad booleana| K[conserva hijos estado y DOM]
M -->|pasa a verdadero| C[crea los hijos una sola vez]
M -->|pasa a falso| F[muestra el fallback]
style K fill:#a6e3a1,color:#11111b
style C fill:#89b4fa,color:#11111b
style F fill:#fab387,color:#11111b
💡
fallback también es perezoso

El fallback no se construye mientras when sea verdadero, y los hijos no se construyen mientras sea falso. Show materializa una sola de las dos ramas a la vez y desecha la otra; no hay coste oculto por la rama inactiva porque, sencillamente, no existe en el DOM. Esto es lo contrario de un render que evalúa todo y luego oculta con CSS.

keyed: recrear al cambiar la identidad

A veces conservar el subárbol es justo lo que no quieres. Si pasas de editar el usuario A al usuario B, un formulario que conserva el borrador de A es un bug. Para eso está keyed: cambia el equals interno a una comparación por identidad —en esencia (a, b) => a === b—, de modo que cualquier cambio de referencia de when, aunque siga siendo truthy, recrea el bloque entero desde cero:

// sin keyed: el subarbol persiste; solo los bindings finos se actualizan
<Show when={usuario()} fallback={<Anonimo />}>
  <Perfil />
</Show>

// con keyed: cada usuario nuevo destruye y reconstruye Perfil
<Show when={usuario()} keyed fallback={<Anonimo />}>
  {(u) => <Perfil id={u.id} />}
</Show>

Fíjate en el segundo detalle: en la forma keyed, el hijo-función recibe el valor ya estrechado directamente (u es NonNullable<T>), no un accesor. Tiene sentido, porque el bloque está atado a la vida de ese valor concreto: cuando el valor cambia, el bloque muere y nace otro con el nuevo u. En la forma sin keyed, en cambio, el hijo-función recibe un accesor que mantiene vivo el subárbol; esa es la forma guard que diseccionaremos en la lección 15.5.

📝
keyed cambia dos cosas a la vez

Activar keyed altera la política de recreación y el tipo del hijo-función. Sin keyed: se conserva el subárbol y el callback recibe Accessor<NonNullable<T>>. Con keyed: se recrea el subárbol en cada cambio de identidad y el callback recibe NonNullable<T>. No son dos features independientes: son las dos caras de “¿este bloque está ligado a la verdad de la condición o a la identidad del valor?”.

Elegir la política: conservar o recrear

La pregunta que decide entre poner o quitar keyed no es de rendimiento, es de corrección: ¿qué debe pasarle al estado del subárbol cuando el valor cambia sin volverse nulo?

🌳

Sin keyed: conservar por verdad

El subárbol persiste mientras when sea truthy. Ideal cuando el contenido representa lo mismo con datos frescos: un panel que muestra el pedido actual, un editor cuyo texto no debe perderse, una vista cuyo scroll importa. El estado sobrevive; los bindings se refrescan.

🔁

Con keyed: recrear por identidad

El subárbol se destruye y reconstruye cuando cambia la referencia. Ideal cuando el valor nuevo es otra entidad: cambiar de usuario, de documento, de sesión. Nada del anterior debe filtrarse; keyed garantiza un lienzo limpio en cada cambio.

Un criterio operativo: si dudas, empieza sin keyed. Conservar es el comportamiento seguro por defecto —evita trabajo y preserva estado— y solo cuando detectes contaminación entre valores distintos (un borrador que se arrastra, un efecto que no se reinicia) añades keyed para forzar el reseteo. Poner keyed “por si acaso” desperdicia recreaciones que no necesitabas.

Show es una política de identidad, no azúcar sintáctico

La tentación al llegar de React es leer Show como un if con estilo. Es un error de categoría. Show es un nodo del grafo reactivo con una decisión de diseño incrustada: su equals define qué significa “cambió la condición”. Por defecto, cambiar significa cruzar la frontera booleana, y entonces conservar el subárbol maximiza la preservación de estado y minimiza el trabajo del DOM —es lo que quieres el noventa por ciento del tiempo—. Con keyed, cambiar significa cambiar de identidad, y entonces recrear garantiza que ningún estado del valor anterior contamine al nuevo. Esa elección —conservar por verdad o recrear por identidad— no es expresable con un && ni con un ternario, porque esos operadores no tienen equals, no tienen memoria de su decisión previa, no tienen concepto de “el mismo bloque, otro valor”. Show sí. Cuando internalices que estás eligiendo una política de identidad cada vez que decides poner o quitar keyed, dejarás de ver Show como sintaxis y empezarás a verlo como lo que es: el punto donde declaras cómo debe reaccionar tu UI a la diferencia entre “otro valor” y “otro estado del mundo”. En el núcleo de Solid 2.0 la evaluación se vuelve más perezosa, pero este contrato —verdad conserva, identidad recrea— se mantiene intacto.

⚔️ Conservar frente a recrear
  1. Monta un Show sin keyed alrededor de un <input> no controlado; escribe algo, cambia when de un truthy a otro truthy y confirma que el texto del input sobrevive.
  2. Añade keyed y repite: comprueba que ahora el input se vacía en cada cambio de identidad.
  3. Explica, en términos del equals interno, por qué el paso 1 conserva y el paso 2 recrea.
  4. Usa un fallback con estado propio y demuestra que la rama inactiva no aparece en el DOM (inspecciona el árbol, no uses display:none).
  5. Con la forma keyed y hijo-función, imprime el id recibido y verifica que llega el valor directo, no un accesor que haya que invocar.