Saltar al contenido

El setter: valor, actualizador y equals

Las dos formas de escribir en un signal —un valor directo o una función actualizadora setCount(c => c + 1)—, la trampa de los signals que guardan funciones, y la opción equals que decide cuándo una escritura re-notifica a los observadores y cuándo se descarta por ser igual.

Dos formas de escribir

El setter acepta, o bien el nuevo valor directamente, o bien una función actualizadora que recibe el valor anterior y devuelve el siguiente. Ambas terminan estableciendo el estado; la diferencia es de dónde sale el valor nuevo.

TSX
const [count, setCount] = createSignal(10);setCount(20);           // valor directo -> 20setCount(c => c + 1);   // actualizador  -> recibe 20, devuelve 21count();                // 21

La forma con función no es adorno. Es la correcta siempre que el valor nuevo dependa del anterior, porque garantiza que operas sobre el estado más reciente sin volver a leer el getter. Esto importa especialmente al agrupar varias escrituras o en código asíncrono, donde una lectura previa de count() podría haber quedado obsoleta:

TSX
// Fragil: lee count() una vez y suma sobre esa fotosetCount(count() + 1);setCount(count() + 1);  // si count() se capturo antes, ambos parten de lo mismo// Robusto: cada actualizador ve el resultado del anteriorsetCount(c => c + 1);setCount(c => c + 1);   // +2 garantizado

El setter, además, devuelve el valor recién establecido, lo que a veces resulta cómodo para registrar o encadenar: const nuevo = setCount(c => c + 1).

La trampa de guardar funciones

De la existencia del actualizador funcional se deriva un peligro concreto y desconcertante. Si tu signal guarda una función —un callback, un manejador—, al hacer setCallback(miFuncion) Solid interpretará miFuncion como un actualizador y la ejecutará pasándole el valor anterior, en lugar de guardarla. El estado acabará siendo lo que esa función devuelva, no la función misma.

TSX
const [callback, setCallback] = createSignal(() => "hola");setCallback(otraFuncion);        // MAL: ejecuta otraFuncion(valorPrevio)setCallback(() => otraFuncion);  // BIEN: el actualizador DEVUELVE la funcion

equals: la decisión de re-notificar

Cada vez que escribes, Solid compara el valor nuevo con el actual y solo notifica a los observadores si son distintos. La comparación por defecto es la igualdad estricta, equivalente a ===. Si estableces el mismo primitivo que ya había, la escritura es un no-op silencioso: ningún efecto se re-ejecuta, ningún memo recalcula.

TSX
const [count, setCount] = createSignal(5);createEffect(() => console.log("valor:", count()));setCount(5);   // igual que antes -> NO re-ejecuta el efectosetCount(6);   // distinto -> el efecto corre

Esto es casi siempre lo que quieres: evita trabajo inútil. Pero tiene una cara incómoda con los objetos, porque === compara referencias, no contenido. Si mutas un objeto y vuelves a establecer la misma referencia, Solid concluye que no ha cambiado y no notifica:

TSX
const [user, setUser] = createSignal({ nombre: "Ada" });const u = user();u.nombre = "Alan";setUser(u);        // misma referencia -> NO notifica: nadie se enterasetUser({ ...u }); // referencia nueva -> SI notifica

La opción equals te da el control. Puedes desactivar la comparación por completo con equals: false para que toda escritura notifique, aunque el valor sea idéntico —útil para señales que actúan como disparadores o que envuelven datos mutables—, o pasar tu propia función de igualdad:

TSX
// Notifica siempre, incluso con el mismo valor:const [ping, setPing] = createSignal(0, { equals: false });// Igualdad a medida: notifica solo si cambia el idconst [item, setItem] = createSignal(dato, {  equals: (prev, next) => prev.id === next.id,});