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.
const [count, setCount] = createSignal(10);setCount(20); // valor directo -> 20setCount(c => c + 1); // actualizador -> recibe 20, devuelve 21count(); // 21La 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:
// 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 garantizadoEl 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.
const [callback, setCallback] = createSignal(() => "hola");setCallback(otraFuncion); // MAL: ejecuta otraFuncion(valorPrevio)setCallback(() => otraFuncion); // BIEN: el actualizador DEVUELVE la funcionequals: 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.
const [count, setCount] = createSignal(5);createEffect(() => console.log("valor:", count()));setCount(5); // igual que antes -> NO re-ejecuta el efectosetCount(6); // distinto -> el efecto correEsto 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:
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 notificaLa 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:
// 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,});