Saltar al contenido

Switch y Match: ramas mutuamente exclusivas

Switch renderiza el primer Match cuyo when es verdadero y un fallback si ninguno acierta. Es el if-else-if reactivo de Solid: exclusividad mutua garantizada, evaluacion en orden y una unica rama montada a la vez.

La firma: Switch envuelve, Match ramifica

Switch no lleva condición propia: es un contenedor que recibe Match como hijos directos y un fallback opcional. Cada Match lleva su when. Switch los evalúa en orden y monta el primero cuyo when sea truthy:

TSX
import { Switch, Match } from "solid-js";<Switch fallback={<p>estado desconocido</p>}>  <Match when={estado() === "cargando"}><Spinner /></Match>  <Match when={estado() === "error"}><ErrorVista error={err()} /></Match>  <Match when={estado() === "listo"}><Datos datos={datos()} /></Match></Switch>

Esto sustituye a una cadena de else if o a un ternario anidado de tres niveles. La diferencia no es solo estética: Switch declara que las ramas son mutuamente excluyentes. El lector no tiene que demostrar, leyendo condiciones cruzadas, que no hay dos ramas que puedan encenderse a la vez; la semántica de “el primero que acierta” lo garantiza por construcción.

El primer Match que acierta: el orden es lógica

Switch recorre sus Match de arriba abajo y se detiene en el primero verdadero. Por eso el orden es parte de la lógica, no un detalle cosmético. Si dos condiciones pueden ser verdaderas a la vez, gana la de arriba:

TSX
// el orden importa: una condicion general arriba TAPA a las especificas<Switch>  <Match when={n() >= 0}><p>no negativo</p></Match>  <Match when={n() === 0}><p>cero</p></Match>  {/* inalcanzable */}</Switch>

Aquí n() === 0 jamás se muestra, porque n() >= 0 ya lo captura. La regla operativa es la misma que en un switch clásico bien escrito: de lo más específico a lo más general, y el caso general —si lo hay— va al fallback, no a un Match final. Cuando ningún Match acierta, Switch monta el fallback; si no hay fallback, no monta nada.

Una sola rama viva: montar destruye la anterior

Aquí está el comportamiento reactivo que hay que interiorizar. Switch mantiene un memo sobre qué índice gana. Mientras el ganador no cambie, no toca el DOM. Cuando el ganador cambia, Switch desmonta la rama anterior —ejecutando sus onCleanup, cancelando sus efectos, liberando su owner— y monta la nueva. No coexisten: la transición es un relevo, no una superposición.

TSX
<Switch>  <Match when={vista() === "mapa"}>    <Mapa />  {/* si vista() pasa a "lista", Mapa se DESTRUYE por completo */}  </Match>  <Match when={vista() === "lista"}>    <Lista />  </Match></Switch>

Esta destrucción es una garantía, no un efecto secundario: el estado, las suscripciones y los nodos DOM de la rama saliente desaparecen limpiamente. Si Mapa abrió un listener de geolocalización en un efecto, su onCleanup corre al cambiar de vista. Por eso Switch es también una herramienta de gestión de recursos: cada rama es un ámbito de vida acotado a que su Match sea el ganador.

Match hereda de Show: keyed y accesor

Match no es un primo lejano de Show: comparte su firma de hijos. Un Match acepta JSX directo o un hijo-función, y obedece las mismas reglas de keyed. Sin keyed, el hijo-función recibe un Accessor<NonNullable<T>> que estrecha el tipo y mantiene vivo el subárbol mientras esa rama gane; con keyed, recibe el valor directo y recrea al cambiar la identidad:

TSX
<Switch fallback={<Anonimo />}>  <Match when={sesion()}>    {(s) => <Perfil usuario={s().nombre} />}   {/* s es accesor, ya no-nulo */}  </Match>  <Match when={invitado()}><Bienvenida /></Match></Switch>

Y como en Show, los hijos-función de Match se envuelven en untrack: la función que produce la rama no crea por sí misma un ámbito de seguimiento sobre el valor; el valor fluye por el accesor, y el seguimiento fino vive en los bindings de dentro. Todo lo que aprendiste de Show sobre memoización por verdad y recreación por identidad se aplica, sin cambios, a cada rama de un Switch. Así, una rama puede pedir keyed para resetear su estado cuando cambia la entidad que representa, mientras las hermanas conservan el suyo:

TSX
<Switch fallback={<Vacio />}>  <Match when={documento()} keyed>    {(doc) => <Editor documento={doc} />}   {/* nuevo doc, editor limpio */}  </Match>  <Match when={cargando()}><Spinner /></Match></Switch>