DEENESH

NOTE–003 · Angular

Angular Signals in real projects

Signals are most useful when they make state easier to follow. They are not a reason to rewrite every observable in an application.

The first examples most developers see of Angular Signals are counters. A value changes, a computed value updates, and the template reflects the result. The API looks simple because the example is simple.

Production applications are different. State may arrive from an API, depend on route parameters, combine several user selections, and trigger work that must be cancelled when the user moves on. The useful question is not “Can I use a signal here?” It is “Will a signal make this state easier to understand?”

Where signals have helped me

Signals work especially well for synchronous UI state owned by a component or feature:

  • the selected item in a table;
  • whether a panel is open;
  • the current filter or sort choice;
  • a loading or validation state;
  • and values derived from other local values.

Computed signals are the part I appreciate most. They let derived state remain derived instead of becoming another value that has to be manually synchronized.

Imagine a list of customer requests with a selected status and search term. The visible rows are a calculation based on the original data and those two inputs. A computed signal can express that relationship directly. When an input changes, Angular recalculates the result. There is no separate subscription whose only job is to assign one property to another.

That removes a common category of bugs: state that was updated in one code path but forgotten in another.

Signals and RxJS are not competitors

I still use RxJS when the problem is a stream.

HTTP requests, debounced searches, route changes, WebSocket events, retry behavior, and work that needs cancellation are naturally modeled with observables. Operators such as switchMap, debounceTime, and catchError describe timing and asynchronous behavior more clearly than a collection of effects.

A practical application often uses both:

  1. RxJS handles the asynchronous sequence.
  2. The result becomes feature state.
  3. Signals and computed values make that state convenient for the template.

Angular’s interop utilities make this boundary manageable, but I try to keep the conversion intentional. Moving repeatedly between signals and observables in the same flow usually makes the code harder to follow.

Be careful with effects

Effects are powerful, and that is why I use them sparingly.

An effect is appropriate when state must synchronize with something outside the reactive model: browser storage, a charting library, logging, or another imperative API. It is less appropriate when it is being used to copy one piece of application state into another. In that situation, a computed value or a clearer data flow is often better.

Too many effects recreate the same problems developers had with scattered subscriptions. The code becomes a network of reactions, and it is difficult to tell which update caused another update.

A migration does not need to be a rewrite

In an established Angular application, I would not replace observables simply to make the code look current. Existing code may already be correct, tested, and understood by the team.

I prefer to introduce signals where they remove real friction:

  • a new standalone component with local state;
  • a feature whose template contains too much manual subscription handling;
  • derived values that are currently synchronized by assignment;
  • or a shared feature store that will become easier to read.

That creates a gradual path and gives the team time to develop conventions.

The standard I use

A state-management choice is successful when another developer can answer three questions quickly:

  1. Where does this value come from?
  2. What can change it?
  3. What depends on it?

Signals can make those answers much clearer. Used everywhere without judgment, they can obscure them again. The goal is not to maximize the number of signals in the codebase. The goal is to make change predictable.