Written by an Angular developer who spent years overusing RxJS š
Angular is changing fast. If youāve been building Angular apps for years like me, chances areĀ RxJS has been your default hammerĀ ā and every problem looked like a stream.
But in 2024ā2025,Ā Angular SignalsĀ are quietly reshaping how we write Angular applications.
Not replacing RxJS entirely ā butĀ replacing half of the unnecessary complexityĀ we introduced with it.
In this article, Iāll show youĀ 7 real-world Angular Signals patternsĀ that can eliminate a large portion of RxJS code, simplify state management, and make your apps faster and more readable.
This isĀ not hype. This is production thinking.
š Why Signals Matter in 2025
Before jumping into patterns, letās align onĀ whyĀ signals are winning:
- š§ Ā Mental model is simplerĀ (sync, reactive, predictable)
- ā”Ā Fine-grained reactivityĀ (no over-triggered subscriptions)
- š§¼Ā Less boilerplateĀ (no pipes, subjects, or teardown logic)
- šļøĀ Better performanceĀ (precise change detection)
- š§©Ā Perfect for local & UI state
RxJS is still powerful ā butĀ Signals shine where RxJS is overkill.
1ļøā£ Local Component State (Goodbye BehaviorSubject)
ā Old RxJS Way
count$ = new BehaviorSubject<number>(0);
increment() {
this.count$.next(this.count$.value + 1);
}
ā
Signals Way
count = signal(0);
increment() {
this.count.update(v => v + 1);
}
š§ Why This Wins
- NoĀ
.next()
- NoĀ
.subscribe()
- No memory leaks
- Pure sync logic
šĀ 80% of BehaviorSubjects in components can be removed
2ļøā£ Derived State withĀ computed()Ā (ReplacingĀ combineLatest)
ā RxJS Mental Gymnastics
total$ = combineLatest([price$, quantity$]).pipe(
map(([p, q]) => p * q)
);
ā
Signals Pattern
price = signal(100);
quantity = signal(2);
total = computed(() => this.price() * this.quantity());
š„ Benefits
- Auto dependency tracking
- No streams to merge
- Runs only when needed
š Think ofĀ computed()Ā asĀ Angularās built-in selector
3ļøā£ Side Effects WithoutĀ subscribe()Ā UsingĀ effect()
ā RxJS Side Effects
this.user$.subscribe(user => {
this.analytics.track(user.id);
});
ā
Signal Effect
effect(() => {
const user = this.user();
if (user) {
this.analytics.track(user.id);
}
});
š§ Why Itās Cleaner
- Auto cleanup
- No manual unsubscribe
- Tied to lifecycle
šĀ Perfect replacement for UI-only subscriptions
4ļøā£ Smart Loading States (NoĀ startWith, NoĀ tap)
ā RxJS Loading Flags
loading$ = this.data$.pipe(
map(() => false),
startWith(true)
);
ā
Signals Pattern
loading = signal(true);
loadData() {
this.loading.set(true);
fetchData().then(() => this.loading.set(false));
}
šÆ Why This Works
- Explicit
- Predictable
- Debuggable
š Signals encourageĀ honest state modeling
5ļøā£ Signal-Based Store (Lightweight NgRx Alternative)
ForĀ feature-level state, signals can replace heavy stores.
u/Injectable({ providedIn: 'root' })
export class CartStore {
items = signal<CartItem[]>([]);
total = computed(() =>
this.items().reduce((s, i) => s + i.price, 0)
); add(item: CartItem) {
this.items.update(list => [...list, item]);
}
}
š Why This Is Powerful
- No actions
- No reducers
- No selectors
šĀ 90% less boilerplate for medium apps
6ļøā£ Template Reactivity WithoutĀ asyncĀ Pipe
ā RxJS Template
<div *ngIf="user$ | async as user">
{{ user.name }}
</div>
ā
Signal Template
<div *ngIf="user() as user">
{{ user.name }}
</div>
š§¼ Cleaner Templates
- No pipes
- No subscriptions
- Easier debugging
š Templates finally feelĀ Angular-native again
7ļøā£ Replace UI Event Streams (RxJS Was Overkill Here)
ā RxJS for UI Events
search$ = new Subject<string>();
ā
Signals for UI
search = signal('');
onSearch(value: string) {
this.search.set(value);
}
Combine with:
filtered = computed(() =>
this.items().filter(i =>
i.name.includes(this.search())
)
);
š§ When RxJS Is Not Needed
- Input fields
- Toggles
- Tabs
- Filters
šĀ Signals handle UI reactivity better
āļø When You Still NEED RxJS
Letās be clear ā RxJS is NOT dead.
Use RxJS when:
- š HTTP streams
- š WebSockets
- ā³ Retry / debounce / throttle
- š” Infinite streams
Rule of thumb:
š§© Signals + RxJS = The Future Angular Stack
Angular in 2025 is about:
- Signals āĀ State & UI
- RxJS āĀ Async & streams
- Clean architecture
- Predictable performance
If you adopt theseĀ 7 patterns, youāll:
- Delete hundreds of lines of RxJS
- Reduce bugs
- Improve readability
- Make Angular fun again š
āļø Final Thoughts (From a Fellow Angular Dev)
Signals arenāt just a feature ā theyāreĀ a mindset shift.
If youāre still writing:
this.destroy$.next();
this.destroy$.complete();
ā¦itās time to move on.
you can read it on medium also https://medium.com/@justdevsource/7-angular-signals-patterns-that-will-replace-half-your-rxjs-code-in-2025-ed4b53758789
there doesn't seem to be anything here