DEV Community

Cristian Sifuentes
Cristian Sifuentes

Posted on

Angular 19 Signals: `update()` vs `.push()` – Why Immutability Matters

angular-signals-update-vs-push

In Angular 19, Signals provide a new way to manage reactive state in a declarative and performant way. But working with arrays in Signals requires understanding a crucial concept: immutability.

If you've written something like this:

this.characters().push(newCharacter);
Enter fullscreen mode Exit fullscreen mode

You might be doing more harm than good. Let’s explore why this is problematic and what the correct approach is using update().


The Problem with .push()

this.characters().push(newCharacter);
Enter fullscreen mode Exit fullscreen mode

This code directly mutates the array returned by the signal. While it appears to work, Angular won’t detect the change, because:

  • The reference to the array hasn't changed.
  • Signals track changes by reference, not by internal mutation.
  • As a result, your UI will not update.

The Correct Way: update()

this.characters.update((prev) => [...prev, newCharacter]);
Enter fullscreen mode Exit fullscreen mode

This is the reactive and immutable way to update a signal.

  • A new array is returned using the spread operator.
  • Angular detects the new reference and triggers reactivity.
  • Any component bound to the signal will automatically reflect the update.

Why Immutability Matters

Signals work best when updates are referentially transparent:

  • They don’t track internal mutations.
  • They react to set() and update() calls where the reference changes.
  • Mutating state in place (like with .push()) breaks reactivity.

Comparison Table

Method Reactive? Immutable? Recommended?
this.characters.update(fn) ✅ Yes ✅ Yes ✅ ✅ ✅
this.characters().push(...) ❌ No ❌ No ❌ Never

Example Use Cases

Add a character:

this.characters.update((prev) => [...prev, newCharacter]);
Enter fullscreen mode Exit fullscreen mode

Remove a character:

this.characters.update((prev) => prev.filter(c => c.id !== target.id));
Enter fullscreen mode Exit fullscreen mode

Replace entire list:

this.characters.set([...newList]);
Enter fullscreen mode Exit fullscreen mode

Final Thoughts

The beauty of Angular Signals is in their predictability and reactivity. But this only works when we respect their design principles.

If you're managing collections in Signals, always use immutable operations through update() or set(). Leave mutation behind—and enjoy fully reactive UIs.

Happy signaling! ⚡

angular #typescript #signals #frontend #architecture

Top comments (1)

Collapse
 
k_h_412a87d7d1e9d31be32 profile image
K. H.

This is written as though everybody is using onPush change detection strategy everywhere. While I agree that most people should in fact use onPush, I doubt it's true that everybody is using that everywhere.

When using default change detection, the arraySignal.push(something) syntax will in fact lead to changes in the UI.