El cambio de mentalidad frente a React
No hay renders. Dejar de pensar en cuándo se re-renderiza y empezar a pensar en el grafo: qué depende de qué. La síntesis del modelo de ejecución de Solid frente a los reflejos de React.
Todo este nivel converge aquí. Lo más difícil de aprender Solid no es su API —es más pequeña que la de React— sino desaprender una sola palabra: render. En Solid no hay renders. No hay “re-render”. La pregunta “¿cuándo se vuelve a renderizar esto?” no tiene respuesta porque presupone un bucle que no existe. Sustitúyela por una mejor: “¿de qué depende esto, y qué depende de ello?”.
- Desmontar el vocabulario de React: render, re-render, ciclo de vida.
- Sustituir “cuándo se re-renderiza” por “qué depende de qué”.
- Traducir los hooks de React a primitivos de Solid sin arrastrar su modelo.
- Consolidar el modelo de ejecución de todo el nivel 6.
Borra la palabra “render”
La diferencia no es de rendimiento, es de ontología. Son dos máquinas distintas:
- React: el componente ES una función de render que corre en cada actualización. Optimizas para que corra menos:
memo,useMemo,useCallback, dividir componentes. - Solid: el componente es una factoría que corre una vez. No hay nada que optimizar en ese sentido: no vuelve a correr nunca.
- React:
useEffect(fn, [deps]); tú declaras las dependencias y un linter te vigila. - Solid:
createEffect(fn); las dependencias se rastrean solas al leer signals dentro. No hay array. - React: un
setStateprovoca el re-render de un subárbol y una reconciliación. - Solid: un signal actualiza solo los efectos y nodos del DOM que lo leen. No hay subárbol, no hay reconciliación.
flowchart TD subgraph React R1[cambia el estado] --> R2[re-render del componente] R2 --> R3[reconciliar virtual DOM] R3 --> R4[parchear el DOM real] end subgraph Solid S1[cambia un signal] --> S2[corren los efectos suscritos] S2 --> S3[parchear el DOM real] end style R2 fill:#f38ba8,color:#11111b style S2 fill:#a6e3a1,color:#11111b
El mismo useEffect que en React vigilas con un array de dependencias, en Solid se escribe sin él y no puede desincronizarse:
// React: si olvidas userId en el array, el efecto usa un valor rancio
useEffect(() => { cargar(userId); }, [userId]);
// Solid: lees userId dentro; la suscripcion es exacta por construccion
createEffect(() => { cargar(userId()); });
Ese array es la fuente de una familia entera de bugs de React —dependencias omitidas, valores rancios, efectos que no se re-disparan— que en Solid no tiene dónde existir, porque nunca declaras dependencias: las lees.
Traduce los reflejos, no la sintaxis
Copiar la sintaxis del hook sin cambiar de modelo es la fuente de la mitad de la frustración. La traducción correcta empieza en la intención:
useState hacia createSignal
El valor se lee llamando: n(), no n. Y el cuerpo no se re-ejecuta al cambiar; solo se actualiza quien lo lee.
useEffect hacia createEffect
Sin array de dependencias: se rastrean solas. Se re-ejecuta al cambiar cualquier signal que leas dentro.
useMemo hacia createMemo
Solo si el derivado es caro o compartido. Para lo simple, una función () => a() + b() basta.
Ternario o if hacia Show y Switch
El flujo de control vive en el JSX para poder reaccionar, jamás en el cuerpo.
Preguntas nuevas para un modelo nuevo
El cambio se nota en las preguntas que dejas de hacerte. Cada ansiedad de React tiene un reemplazo o simplemente desaparece:
- En vez de “¿por qué se re-renderiza de más?”, pregunta “¿qué efecto se re-ejecuta y qué signal lo dispara?”.
- En vez de “¿debo envolver esto en
useMemo?”, pregunta “¿este derivado es caro o compartido? EntoncescreateMemo; si no, una función basta”. - En vez de “¿están bien mis dependencias?”, nada: no hay array. Lee el signal donde lo necesites y ya queda suscrito.
- En vez de “¿este objeto rompe la igualdad referencial?”, nada: no hay comparación de props ni de árboles. El problema no existe.
// React: memoizar para no recalcular en cada render
const total = useMemo(() => items.reduce(suma, 0), [items]);
// Solid: los items son un signal; el derivado se recalcula solo si cambian
const total = createMemo(() => items().reduce(suma, 0));
// y si es barato, ni memo: const total = () => items().reduce(suma, 0);
El patrón se repite en toda la API. Cada pieza de React que existía para controlar el render —memo, useMemo, useCallback, useRef para estabilizar identidades— no tiene contraparte en Solid, porque no hay render que controlar. La API no es más pequeña por elegancia: lo es porque la mitad de la de React resolvía un problema que aquí no existe.
Al portar un componente, no busques el equivalente uno a uno de cada hook. Pregúntate qué intentaba lograr: “esto deriva un valor” se vuelve una función o un createMemo; “esto sincroniza con el exterior” se vuelve un createEffect; “esto evita recrear” se borra, porque nada se recrea. La traducción literal produce Solid que funciona pero piensa en React; la de intención produce Solid de verdad.
Lo que ganas al soltar el render
El cambio no es solo conceptual; tiene consecuencias muy concretas en el código que escribes y en el que ya no escribes:
- Desaparece la memoización defensiva. No hay
useCallbacknimemode componente porque no hay identidad de función que estabilizar entre renders. Un handler declarado en el cuerpo se crea una vez y es estable por construcción. - Desaparecen los arrays de dependencias. El rastreo es automático y exacto: nunca “olvidas” una dependencia ni suscribes de más. El linter deja de pedirte listas.
- El estado profundo es barato. Con
createStore, mutarestado.a.b.csolo notifica a quien leyó ese camino; no clonas objetos ni comparas árboles para detectar el cambio. - La granularidad es del tamaño de un nodo. Actualizar un texto toca un
textContent, no re-ejecuta un componente ni difunde un re-render hacia abajo.
// React: el handler cambia de identidad salvo que lo memoices
const alClic = useCallback(() => setN((n) => n + 1), []);
// Solid: se declara una vez, es estable, no hay nada que memoizar
const alClic = () => setN(n() + 1);
Ninguna de estas ventajas es un “modo optimizado” que actives: son la consecuencia de no tener un render que repetir. El trabajo que en React dedicabas a controlar el bucle, en Solid simplemente no existe, y ese hueco es el que ocupa la claridad del grafo.
Y cuando de verdad buscas rendimiento extremo, el camino no es memoizar más, sino afinar el grafo: compartir un cálculo con createMemo, o agrupar varias escrituras con batch para propagarlas en una sola pasada.
import { batch } from "solid-js";
// una sola propagacion aunque muevas tres signals
batch(() => {
setNombre("Ada");
setEdad(36);
setActivo(true);
});
Ninguno de estos ajustes se parece a “evitar renders”: todos son “dar forma al grafo”. Ese es, exactamente, el vocabulario nuevo que sustituye al viejo.
Casi todo lo que cuesta al llegar de React es soltar reflejos, no adquirir conceptos. La API de Solid es pequeña; lo difícil es dejar de destructurar props, dejar de meter if en el cuerpo, dejar de pensar en “cuándo se re-renderiza”. Si te sorprendes optimizando para evitar renders, es la señal de que aún arrastras el modelo viejo. El día que la palabra “render” deja de aparecer en tu cabeza, Solid se vuelve, de golpe, el framework más simple que has usado.
La promesa de este nivel es una sola frase que por fin puedes oír bien: en Solid no hay render. Ni un render rápido, ni un render optimizado —ninguno—. Hay un grafo de signals, memos y efectos, construido una vez por el cuerpo, y un mecanismo de propagación que, cuando un signal cambia, despierta exactamente los nodos que dependen de él y ningún otro. Todo lo que React te enseñó a vigilar —memoizar para evitar re-renders, estabilizar referencias, afinar arrays de dependencias, trocear componentes para reducir la superficie de render— era trabajo al servicio de un virtual DOM que Solid sencillamente no tiene. Cuando borras la palabra “render” de tu vocabulario, se borra con ella una cascada de ansiedades. Dejas de preguntar cuándo se re-ejecutan las cosas y empiezas a describir qué depende de qué. Dejas de optimizar un bucle y empiezas a dibujar un grafo. Y descubres que el grafo, bien dibujado, casi no necesita optimización, porque su granularidad ya es la más fina posible: un efecto por expresión reactiva, actualizando un nodo del DOM. Eso no es un truco atornillado a un framework. Es el framework. Bienvenido a pensar en signals.
- Toma un componente React que conozcas con
useState,useEffectyuseMemo, y tradúcelo a Solid sin arrastrar la mentalidad de render. - Por cada
useMemodel original, decide si en Solid necesitacreateMemoo basta una función. Justifícalo. - Elimina todo array de dependencias: reescribe los efectos leyendo los signals dentro y confirma que se rastrean solos.
- Escribe en una frase, sin usar la palabra “render”, qué ocurre en Solid cuando cambia un signal. Esa frase es tu modelo de ejecución.
- Busca en el original cada
useCallbackouseMemoque ya no necesitas y bórralo: lo que sobra al traducir es, exactamente, el peso del modelo de render.