wandres.dev
LIFECYCLE Y REFS · onMount, ciclo de vida

No hay lifecycle de update

Por qué Solid no tiene un hook de actualización equivalente a componentDidUpdate o a useEffect con dependencias: el cuerpo corre una vez y no existe un re-render que interceptar. Reaccionar a cambios se hace con efectos que rastrean sus lecturas, con el valor previo para comparar, y con on más defer para correr solo en los cambios posteriores y no en el montaje.

⏱ 13 min

En los frameworks con re-render existe un hueco natural llamado “actualización”: el momento entre un render y el siguiente, donde enganchas componentDidUpdate o un useEffect con dependencias para reaccionar a lo que cambió. En Solid ese hueco no existe, porque no existe el siguiente render: el cuerpo corre una vez y nunca vuelve. Y sin embargo tu interfaz reacciona a los cambios mejor que nunca. La clave es que reaccionar no es un momento del ciclo de vida que interceptas, sino una relación que declaras: un efecto que rastrea lo que lee y se re-ejecuta solo cuando eso cambia.

🎯 Al terminar esta lección sabrás
  • Entender por qué no hay un hook de “update”: sin re-render, no hay nada que interceptar.
  • Reaccionar a un cambio con un createEffect que rastrea las lecturas que le importan.
  • Comparar el valor nuevo con el anterior usando el prev del efecto.
  • Correr solo en los cambios posteriores con on(deps, fn, { defer: true }).

El hueco que no existe

En React, el modelo mental de “reaccionar” está ligado al render: el componente se vuelve a ejecutar, y hooks como componentDidUpdate o useEffect(fn, [dep]) te dan un lugar donde correr después de ese nuevo render. La pregunta que te haces es temporal: “¿qué hago cuando el componente se actualiza?”.

Solid borra esa pregunta. El cuerpo del componente es una factoría que corre una vez, construye el grafo reactivo y termina. No hay un segundo pase, ningún “el componente se actualizó”, ningún array de dependencias que comparar entre renders. Buscar un onUpdate en Solid es buscar un objeto que el modelo no contiene.

Lo que sí hay es reactividad de grano fino. En vez de un hook que corre tras cada render, declaras un efecto que se suscribe exactamente a los signals que lee y se re-ejecuta solo cuando alguno cambia.

import { createEffect } from "solid-js";

function Titulo(props: { nombre: string }) {
  createEffect(() => {
    document.title = `Hola, ${props.nombre}`;   // corre al montar y cuando props.nombre cambia
  });
  return <h1>{props.nombre}</h1>;
}

Ese efecto no necesita saber “el componente se actualizó”. Sabe algo más preciso: props.nombre cambió. No reacciona a un render global, reacciona a un dato concreto.

flowchart TD
subgraph React
  A[cambia el estado] --> B[re-render del componente]
  B --> C[componentDidUpdate corre despues]
end
subgraph Solid
  D[cambia un signal] --> E[solo se re-ejecuta el efecto suscrito]
end
style B fill:#f38ba8,color:#11111b
style E fill:#a6e3a1,color:#11111b

De componentDidUpdate a un efecto

La traducción es directa: donde en React pondrías la lógica de actualización en un hook que observa una dependencia, en Solid pones un efecto que lee esa dependencia. El acto de leerla es lo que crea la suscripción; no hay que declararla en un array aparte.

// React: la dependencia se declara en un array, un lint la vigila
useEffect(() => {
  sincronizar(userId);
}, [userId]);

// Solid: la dependencia se descubre leyendola dentro del efecto
createEffect(() => {
  sincronizar(props.userId);
});

Esto elimina de raíz una familia entera de bugs. No hay dependencias omitidas ni de más, porque no se declaran: se rastrean. No hay closures obsoletas por un array desactualizado, porque el efecto siempre lee el valor vigente. La correspondencia entre “de qué depende” y “qué observa” es automática, no una lista que mantener sincronizada con la lógica.

Cuando necesitas comparar el valor nuevo con el anterior —algo que en React harías guardando un ref con el valor previo— Solid te lo da integrado: el efecto puede recibir su propio retorno anterior.

createEffect((anterior) => {
  const actual = props.pagina;
  if (anterior !== undefined && actual !== anterior) {
    registrarNavegacion(anterior, actual);   // solo cuando de verdad cambio
  }
  return actual;                             // sera el `anterior` del proximo run
}, undefined);

on con defer: reaccionar solo a los cambios

Queda un matiz. Un createEffect corre también en el montaje, no solo en los cambios posteriores; su primera ejecución es parte del arranque. A veces eso es justo lo que no quieres: la semántica exacta de componentDidUpdate es “corre en las actualizaciones, pero no en el montaje inicial”.

Para eso Solid ofrece on, un ayudante que hace explícitas las dependencias y acepta la opción defer. Con { defer: true } el efecto salta su primera ejecución y solo corre a partir del siguiente cambio: la reproducción precisa del hook de actualización.

import { createEffect, on } from "solid-js";

function Filtro(props: { consulta: string }) {
  createEffect(
    on(
      () => props.consulta,
      (consulta, anterior) => {
        // NO corre al montar; solo cuando props.consulta cambia
        buscar(consulta, { desde: anterior });
      },
      { defer: true }
    )
  );
  return <div>...</div>;
}

on invierte la ergonomía por defecto: en vez de descubrir dependencias leyéndolas en cualquier punto del cuerpo, las enumeras en el primer argumento y el cuerpo del segundo queda sin rastreo, de modo que lo que leas dentro no crea suscripciones nuevas. Es la herramienta para cuando quieres control quirúrgico sobre qué dispara el efecto y si el primer run cuenta o no.

💡
Elige por defecto el efecto que rastrea; usa on para lo explícito

Para el 90 % de los casos, un createEffect que simplemente lee lo que necesita es lo correcto: menos ceremonia, cero listas de dependencias, imposible desincronizar. Recurre a on cuando de verdad quieras acotar las dependencias a mano —porque el cuerpo lee más signals de los que deben disparar el efecto— o cuando necesites defer para saltar el montaje. No conviertas on en tu forma normal de escribir efectos: es la excepción con intención, no el estilo por defecto.

De los hooks de ciclo de vida a las primitivas reactivas, el diccionario de traducción es corto:

🚀

componentDidMount

onMount: el trabajo de arranque una vez que el DOM existe.

🔄

componentDidUpdate

createEffect que lee la dependencia, o on con defer para saltar el montaje.

🧹

componentWillUnmount

onCleanup: libera lo reservado cuando muere el dueño.

🎯

useEffect con deps

createEffect sin array: las dependencias se rastrean al leerlas, no se declaran.

Reaccionar es una relación declarada, no un momento interceptado

El salto conceptual de este nivel es dejar de pensar el tiempo del componente como una sucesión de renders con huecos entre ellos —montaje, actualización, actualización, desmontaje— donde enganchas código en cada hueco. En Solid solo hay dos hechos: la construcción, que ocurre una vez, y la propagación reactiva, que ocurre para siempre y de forma dirigida. No existe un “durante la actualización” porque no existe la actualización como evento global; existen signals que cambian y efectos que, por haber leído esos signals, se re-ejecutan sin que nada más se entere. Esto invierte la pregunta que traías de React. Allí preguntabas “¿en qué momento del ciclo de vida corro esto?” y elegías un hook. Aquí preguntas “¿de qué dato depende esto?” y lo lees dentro de un efecto; el cuándo se deduce solo del qué. La consecuencia es que la clase entera de errores de sincronización —dependencias mal declaradas, efectos que corren de más o de menos, valores obsoletos capturados en un render viejo— simplemente no tiene dónde ocurrir, porque nunca separaste la dependencia de su observación. Cuando de verdad quieras la semántica fina de “solo en los cambios, no al montar”, on con defer te la da; pero es un ajuste sobre un modelo que ya reacciona correctamente, no un parche para un hueco que faltaba.

⚔️ Reacciona sin un hook de update
  1. Escribe un efecto que actualice document.title cuando cambie una prop, y confirma que corre al montar y en cada cambio.
  2. Convierte un useEffect(fn, [dep]) de React que conozcas en un createEffect de Solid y anota qué desaparece (el array).
  3. Usa el prev del efecto para registrar un cambio solo cuando el valor nuevo difiere del anterior.
  4. Reescribe ese efecto con on(deps, fn, { defer: true }) para que NO corra en el montaje.
  5. Explica en una frase por qué en Solid no hace falta un hook equivalente a componentDidUpdate.