wandres.dev
SETUP Y JSX DE SOLID · no es React

Diferencias con el JSX de React

Los desajustes concretos que tropiezan a quien llega de React: class en vez de className, for en vez de htmlFor, el objeto style con nombres CSS y unidades explícitas, la ausencia de keys, y los refs como variables asignadas o callbacks en lugar de useRef y .current.

⏱ 12 min

El JSX de Solid se parece tanto al de React que la confusión no viene de lo distinto, sino de lo casi-igual. Un puñado de atributos cambian de nombre, el objeto de estilos sigue otra convención, las listas no llevan clave y las referencias al DOM se resuelven sin hooks. Ninguna diferencia es capricho: cada una cae de que Solid emite atributos HTML reales en vez de alimentar un reconciliador. Este es el mapa de los tropiezos, uno por uno.

🎯 Al terminar esta lección sabrás
  • Usar class y for como en HTML, y classList para clases condicionales.
  • Escribir el objeto style con nombres CSS y unidades explícitas, no camelCase.
  • Entender por qué en Solid no existe la prop key y qué la sustituye.
  • Capturar nodos del DOM con ref como variable o callback, sin useRef ni .current.

Atributos que vuelven al HTML

React inventó className y htmlFor porque class y for son palabras reservadas de JavaScript, y sus elementos son objetos cuyas propiedades chocaban con ellas. Solid no fabrica objetos: escribe atributos sobre nodos reales, así que recupera los nombres del HTML de toda la vida.

// React                          // Solid
<div className="card" />          <div class="card" />
<label htmlFor="email" />         <label for="email" />

Para clases condicionales, React te obliga a concatenar cadenas o a tirar de librerías. Solid ofrece dos herramientas nativas: el atributo classList, que recibe un objeto de clase a booleano, y el namespace class: para una sola clase. Ambos actualizan cada clase de forma independiente y reactiva.

// objeto: cada clave se activa segun su booleano
<button classList={{ activo: seleccionado(), grande: esGrande() }} />

// namespace: una unica clase, mismo efecto
<button class:activo={seleccionado()} />

Solid tolera className y htmlFor como alias por compatibilidad, pero conviene leerlos como una señal de que aún piensas en React: lo idiomático es class y for. Esa misma vuelta al HTML rige para los atributos de SVG y para los data-* y aria-*, que se escriben literalmente, sin recamelizar.

El objeto style: nombres CSS y unidades

Aquí está el desajuste que más silenciosamente rompe cosas. En React el objeto de estilos usa camelCase y añade px por ti: {{ backgroundColor: "red", fontSize: 16 }}. En Solid el objeto de estilos habla CSS literal: las claves son propiedades CSS en kebab-case y los valores llevan unidad explícita, porque Solid las asigna tal cual sin interpretarlas.

// React
<p style={{ backgroundColor: "red", fontSize: 16 }} />

// Solid: nombres CSS y unidades a mano
<p style={{ "background-color": "red", "font-size": "16px" }} />

Olvidar el px es el error clásico: fontSize: 16 en Solid no hace nada, porque font-size: 16 no es CSS válido. A cambio, este objeto acepta cosas que el de React no maneja con naturalidad, como variables CSS personalizadas, y admite el namespace style: para una propiedad suelta.

// variables CSS y propiedad individual reactiva
<div style={{ "--acento": color() }} />
<div style:width={`${ancho()}px`} />

El objeto no es la única forma: style acepta también una cadena CSS completa —útil cuando el estilo llega ya serializado desde otra fuente—, aunque con cadena Solid reemplaza el bloque entero en cada cambio mientras que con objeto actualiza cada propiedad por separado. Prefiere el objeto siempre que puedas.

⚠️
El px que no está y el estilo que no aparece

Si un estilo dinámico no surte efecto, sospecha primero de la unidad. Solid no adivina que 16 significa 16px: pasa el valor crudo al DOM, y el navegador descarta lo que no es CSS legal. La regla es mecánica: en el objeto style de Solid, todo valor con dimensión lleva su unidad escrita a mano. Es más verboso que React, pero también más predecible, porque no hay una capa oculta decidiendo qué propiedades reciben px y cuáles no.

No hay keys: la lista se reconcilia por referencia

En React, key es la pista que orienta al reconciliador para emparejar elementos entre renders. Solid no reconcilia listas comparando árboles, así que la prop key no existe en su JSX. En su lugar tienes dos componentes de control de flujo con estrategias opuestas.

🔗

For, indexado por referencia

<For each={items()}> empareja cada elemento por su identidad en memoria. Reordenar el array mueve nodos del DOM sin recrearlos; solo altas y bajas crean o destruyen. Es el que quieres para listas de objetos.

🔢

Index, indexado por posición

<Index each={items()}> fija cada fila a su posición. El nodo persiste y lo que cambia es su contenido reactivo. Ideal para primitivos o campos de formulario donde la posición manda.

// el hijo es una funcion; recibe el item (como signal en For)
<For each={usuarios()}>
  {(u) => <li>{u.nombre}</li>}
</For>

Con <Index> el patrón se invierte: el hijo recibe una señal, porque lo que persiste es la posición y lo que varía es el contenido de esa fila.

// en Index el item llega como signal: color() lee el valor de la fila
<Index each={colores()}>
  {(color, i) => <li>{i + 1}: {color()}</li>}
</Index>

La ausencia de key desconcierta al principio, pero es coherente: no le das una pista a un algoritmo de diffing porque no hay tal algoritmo. Eliges la semántica —identidad o posición— seleccionando el componente, y Solid mueve o parchea nodos en consecuencia.

Refs: variables y callbacks, sin .current

React captura nodos con useRef y accede a ellos por .current, un objeto mutable que sobrevive a los renders. Solid, como el componente corre una vez, no necesita ese envoltorio: ref acepta directamente una variable que el compilador asigna, o una función callback que recibe el nodo.

function Campo() {
  let entrada;                       // variable local, sin useRef

  onMount(() => entrada.focus());    // ya apunta al nodo real

  return <input ref={entrada} type="text" />;
}

La forma variable es azúcar del compilador: ref={entrada} se traduce en entrada = elNodo en el momento de crearlo. La forma callback es más flexible y sirve cuando necesitas lógica en el instante de la conexión, o para reenviar la referencia hacia arriba.

// callback: se invoca con el nodo al montarse
<input ref={(el) => configurar(el)} />

Reenviar una referencia a través de un componente hijo no necesita API especial: el hijo recibe ref como una prop más y se la entrega a su nodo. Como ref admite tanto variable como función, el padre puede pasar cualquiera de las dos y el hijo la propaga sin enterarse de cuál es.

function Campo(props) {
  return <input ref={props.ref} />;   // reenvia la referencia del padre
}

// el padre captura el input como si fuera suyo
let entrada;
<Campo ref={entrada} />;
💡
El ref ya está listo, pero espera a onMount

La variable de un ref queda asignada al crear el nodo, antes de que esté en el documento. Si vas a medirlo, enfocarlo o pasarlo a una librería del DOM, hazlo dentro de onMount, que se dispara cuando el árbol ya está insertado. Acceder al ref en el cuerpo del componente te da el nodo, sí, pero todavía huérfano del documento: mediciones y focos fallarán silenciosamente.

Casi-igual es más peligroso que distinto

La trampa de venir de React a Solid no son las diferencias grandes y visibles, sino las pequeñas y silenciosas. Un framework radicalmente distinto te obliga a aprender de cero y bajas la guardia con humildad; uno casi idéntico te invita a proyectar tus reflejos, y los reflejos equivocados no lanzan errores, simplemente no funcionan. Escribes className y Solid, tolerante, hasta lo acepta como alias; escribes fontSize: 16 y no pasa nada visible; buscas key y no lo encuentras y asumes que lo olvidaste. Cada uno de estos desajustes tiene la misma raíz y conviene grabársela: Solid no interpreta tu JSX en tiempo de ejecución, lo compila a manipulación directa del DOM. Por eso los nombres vuelven al HTML —class, for—, por eso el style es CSS crudo sin azúcar de unidades, por eso no hay key que oriente un diff inexistente, y por eso un ref es solo una variable a la que se le asigna un nodo. No memorices las diferencias como una lista de excepciones; deriva cada una del principio de que Solid emite DOM real. Quien entiende la causa deja de tropezar, porque predice la regla en vez de recordarla. Y ese es el salto de quien traduce React palabra por palabra a quien piensa en Solid.

⚔️ Traduce reflejos de React a Solid
  1. Escribe un componente con class, un classList de dos clases condicionales y un for que enlace un label con su input.
  2. Aplica un style dinámico con font-size y una variable CSS --acento; quítale la unidad al font-size y observa cómo el estilo desaparece.
  3. Renderiza una lista con <For> y otra con <Index> sobre el mismo array; reordena los datos y compara qué nodos se mueven y cuáles se reescriben.
  4. Captura un input con un ref de variable y enfócalo dentro de onMount; luego reescríbelo con la forma callback.