Saltar al contenido

El valor previo y la limpieza

El efecto puede pasarse un valor a sí mismo entre ejecuciones con createEffect prev e inicial, y liberar lo que reservó con onCleanup antes de cada rerun y al destruirse el dueño. Setup y teardown simétricos.

El valor que el efecto se pasa a sí mismo

createEffect acepta un segundo argumento: un valor inicial. Cuando lo das, la función del efecto recibe como parámetro el valor que devolvió la ejecución anterior; en el primer run recibe el inicial.

Así el efecto puede hilar una ejecución con la siguiente sin necesidad de un signal externo que haga de memoria.

TSX
import { createSignal, createEffect } from "solid-js";const [n, setN] = createSignal(0);createEffect((anterior) => {  const actual = n();  if (anterior !== actual) {    console.log(`cambio de ${anterior} a ${actual}`);  }  return actual; // se convierte en el `anterior` del proximo run}, n());

Es el patrón del acumulador. El retorno del efecto no lo consume el grafo —recuerda que un efecto es una hoja—, pero sí lo consume el propio efecto en su siguiente iteración.

Sirve para detectar la dirección de un cambio, mantener un máximo histórico, o conservar entre reruns un objeto costoso de recrear.

TSX
createEffect((maxPrevio) => {  const v = valor();  return v > maxPrevio ? v : maxPrevio; // maximo sostenido sin signal extra}, -Infinity);

onCleanup: soltar lo que reservaste

La mayoría de los efectos que tocan el mundo real reservan algo: un temporizador, un listener del DOM, una suscripción, un socket. Si el efecto vuelve a correr o el componente desaparece, ese recurso debe liberarse, o tendrás una fuga.

onCleanup registra una función de limpieza que Solid ejecutará en dos momentos: justo antes de la siguiente ejecución del efecto, y cuando el dueño del efecto se destruye.

TSX
import { createEffect, onCleanup } from "solid-js";createEffect(() => {  const id = canal();  const socket = abrirSocket(id);  onCleanup(() => socket.cerrar());});

Sigue la coreografía cuando canal cambia de a a b. Solid ejecuta primero la limpieza registrada en el run anterior —cierra el socket de a—, y solo entonces corre de nuevo el cuerpo, que abre el socket de b y registra una nueva limpieza.

Cuando el componente se desmonta, se ejecuta la última limpieza pendiente y el socket de b se cierra también. En ningún momento hay dos sockets abiertos ni uno huérfano.

El caso más frecuente es un listener del DOM o un intervalo. El patrón es siempre el mismo: abre en el cuerpo, cierra en el onCleanup inmediato.

TSX
createEffect(() => {  const onScroll = () => setY(window.scrollY);  window.addEventListener("scroll", onScroll);  onCleanup(() => window.removeEventListener("scroll", onScroll));});

Puedes registrar varias limpiezas en un mismo efecto —una por cada recurso—, y todas se ejecutan al llegar el momento. La regla de oro es la simetría: cada cosa que abres, ciérrala en su onCleanup, lo más cerca posible de donde la abriste. Así el montaje y el desmontaje se leen juntos y ninguno se olvida.

Un ciclo de vida atado al dueño

onCleanup no funciona por magia global: se apoya en el árbol de ownership de Solid. Todo efecto tiene un dueño —el componente, el createRoot o el efecto padre en cuyo contexto se creó—, y su limpieza queda enganchada a ese dueño.

Cuando el dueño se destruye, Solid recorre a sus hijos y ejecuta todas sus limpiezas en cascada. No hay que desmontar nada a mano: la disposición es automática y determinista.

Esto es lo que hace que un efecto sea un ciclo de vida completo y no un disparo suelto. El primer run es el montaje; cada rerun es un remontaje precedido de su limpieza; la destrucción del dueño es el desmontaje final. Todo el arco vive en un solo bloque, junto a la lógica que lo motiva, en lugar de repartido entre un onMount y un onUnmount que hay que mantener sincronizados.