Saltar al contenido

Por que no usar && ni ternarios crudos

Los operadores nativos del JSX reaccionan en Solid, pero and-and filtra valores falsy al DOM y ni el ternario ni el and te dan fallback, keyed, accesor estrechado ni exclusividad declarada. Que pierdes exactamente frente a Show y Switch.

El operador && inserta el 0

El fallo más concreto y frecuente. a && b en JavaScript no devuelve un booleano: devuelve a si a es falsy, y b si no. Cuando a es 0, "" o NaN, el operador devuelve ese valor falsy, y Solid lo inserta como texto en el DOM:

TSX
// BUG clasico: si carrito().length es 0, aparece un "0" suelto en pantalla<div>{carrito().length && <Badge n={carrito().length} />}</div>

Cuando el carrito está vacío, carrito().length es 0, la expresión completa evalúa a 0, y el usuario ve un 0 fantasma donde esperaba nada. El parche habitual —carrito().length > 0 && ...— funciona, pero es justo eso, un parche que recuerda que el operador no coerciona. Show no tiene este problema por diseño: su prop when acepta T | undefined | null | false y coerciona la verdad, así que un 0 es simplemente falso y se muestra el fallback o nada:

TSX
<Show when={carrito().length}>  <Badge n={carrito().length} /></Show>

La fuga no se limita a .length. Cualquier expresión que a la izquierda de && produzca 0, "" o NaN termina impresa: precio() && ... escupe un 0 cuando el precio es cero, nombre() && ... no imprime nada solo por suerte —una cadena vacía es falsy y se inserta como texto vacío, pero un 0 numérico se ve—. La lección es que && no coerciona: reenvía el operando izquierdo tal cual, y Solid lo pinta. Show coerciona siempre; el operador, nunca.

Reaccionan, sí, pero no es una política de identidad

El compilador de Solid envuelve los condicionales inline en un memo, así que un ternario simple cond() ? <A /> : <B /> no recrea sus ramas en cada cambio de dependencia: se comporta parecido a Show para el vaivén verdadero↔falso. Hasta aquí, empate aparente. La grieta aparece cuando necesitas algo más que “esto o aquello”:

  • Esa memoización es una optimización implícita del compilador, atada a que reconozca sintácticamente el condicional en una posición insertable. En cuanto mueves la condición a una variable, la devuelves desde una función auxiliar o construyes una expresión más enrevesada, la garantía se difumina y puedes acabar recreando el subárbol en cada cambio. Show hace esa frontera explícita e incondicional: memoiza la verdad siempre, sin depender de la forma del código.
  • El operador crudo no tiene equals, no tiene memoria de su decisión previa, no tiene el concepto de “el mismo bloque, otro valor”. Por eso no puede expresar keyed: no hay forma de decir “recrea este bloque cuando cambie la identidad, aunque siga siendo verdadero”. Esa política de identidad —el corazón de la lección 15.1— sencillamente no existe fuera de Show y Match.

Reaccionar es el mínimo. Show te da, además, control sobre cómo reacciona: conservar por verdad o recrear por identidad. El ternario te da lo primero y te niega lo segundo.

La fragilidad de esa memoización implícita se ve mejor con código. El compilador solo la aplica cuando reconoce el condicional dentro del JSX:

TSX
// bien: condicional inline; el compilador lo envuelve en un memo<div>{cond() ? <A /> : <B />}</div>// mal: al sacar la decision del JSX, ni siquiera reaccionaconst rama = cond() ? <A /> : <B />;   // se evalua UNA vez en el cuerpo<div>{rama}</div>

El segundo caso es un recordatorio brutal de la lección 6: el cuerpo del componente corre una sola vez, así que rama se calcula una vez y se queda congelada; el ternario ahí no es reactivo en absoluto. El condicional reactivo tiene que vivir dentro del JSX y con la forma exacta que el compilador sabe rastrear. Show, al ser un componente, no depende de esa forma: memoiza siempre, lo pongas donde lo pongas, lo asignes a una variable o lo devuelvas de una función. La reactividad del operador es un privilegio sintáctico; la de Show, un contrato.

El ciclo de creación y destrucción

Volvamos al subtítulo de la lección: cómo Solid crea y destruye. Cuando una condición cambia de rama —da igual si con Show o con un ternario— Solid ejecuta un ciclo preciso: desmonta la rama saliente, corriendo sus onCleanup, cancelando sus efectos, liberando su owner y quitando sus nodos del DOM, y monta la entrante, creando sus nodos, arrancando sus efectos y registrando sus limpiezas. No hay superposición ni reconciliación de árboles: es un relevo limpio.

La diferencia entre las dos herramientas no es si ocurre ese ciclo, sino quién decide cuándo y con qué control. Show ata el ciclo a un memo de la verdad que tú gobiernas: sin keyed, dispara solo al cruzar falso↔verdadero y conserva el subárbol en medio; con keyed, dispara también al cambiar la identidad. Un operador crudo ata el ciclo al memo implícito que el compilador coloca por ti, sin fallback con vida propia, sin keyed y sin accesor estrechado:

TSX
// con Show controlas el ciclo: conserva por defecto, resetea con keyed<Show when={pedido()} keyed>{(p) => <Detalle pedido={p} />}</Show>// con el ternario obtienes el relevo, pero sin palancas:// ni fallback nombrado, ni politica de identidad, ni tipo estrechado{pedido() ? <Detalle pedido={pedido()!} /> : <Vacio />}

Ese es el sentido exacto de “qué pierdes”: no pierdes reactividad ni pierdes el ciclo de creación y destrucción —ambos siguen ahí—, pierdes las palancas para dirigirlo. El operador te da el motor; Show y Switch te dan además el volante.

Lo que pierdes, punto por punto

Ninguna de estas pérdidas es sintáctica; todas son de capacidad. El operador crudo es un condicional de propósito general que resulta reactivo; Show y Switch son condicionales diseñados para el grafo, con lifecycle, política de identidad y estrechamiento de tipos incorporados.