RxJS in Angular 2026: operators, Subjects en Signals-interop
RxJS in Angular 2026: de operators, Subjects en Signals-interop-patronen die Angular-ontwikkelaars in productie gebruiken, plus de meest voorkomende sollicitatievragen.

RxJS blijft in Angular ook in 2026 de ruggengraat van asynchroon programmeren, ook al veranderen Signals hoe Angular-componenten synchrone state bijhouden. Weten wanneer een Observable de juiste keuze is, wanneer een Signal beter past en hoe beide samenwerken, hoort inmiddels tot de kernvaardigheden van elke Angular-ontwikkelaar. Deze deep dive loopt door de operators, Subjects en interop-patronen die een zelfverzekerd sollicitatieantwoord onderscheiden van een dat vastloopt.
Signals modelleren synchrone state die altijd een huidige waarde heeft; Observables modelleren asynchrone stromen van gebeurtenissen in de tijd. Angular 20 behoudt beide, en het pakket @angular/core/rxjs-interop is de officiële brug ertussen.
Waarom RxJS naast Angular Signals nog steeds telt
De introductie van Signals bracht veel teams ertoe zich af te vragen of RxJS op zijn retour was. Het antwoord luidt drie hoofdversies later: nee. Signals blinken uit in het weergeven van state die nu een waarde heeft: een teller, een formulierveld, een geselecteerde tab. Observables blinken uit in het modelleren van gebeurtenissen die in de tijd binnenkomen en transformatie, annulering of combinatie kunnen vereisen: HTTP-antwoorden, WebSocket-berichten, toetsenbordinvoer, router-gebeurtenissen en timers.
Angulars eigen API's maken deze scheiding zichtbaar. HttpClient levert nog altijd Observables. Reactive forms stellen valueChanges en statusChanges als Observables beschikbaar. Router-gebeurtenissen stromen door een Observable. Overal waar meerdere asynchrone gebeurtenissen door hetzelfde kanaal vloeien, blijven RxJS-operators het meest expressieve gereedschap dat er is. De officiële Angular-gids over reactiviteit behandelt beide modellen als aanvullend in plaats van concurrerend, en de RxJS-documentatie blijft een verplichte referentie voor elke niet-triviale datastroom.
De praktische regel die standhoudt in code review: Signals voor lokale componenten-state die in templates wordt gelezen, en Observables voor asynchrone pipelines die operators nodig hebben. De interop-laag verbindt beide, zodat geen van beide modellen een muur wordt.
Combinatie-operators onderstrepen dit punt. Meerdere asynchrone bronnen coördineren, zoals routeparameters samenvoegen met de opgeslagen filters van een gebruiker en een live prijsfeed, is precies waarvoor combineLatest, withLatestFrom en forkJoin zijn gebouwd. Signals kunnen berekende waarden afleiden uit andere signals, maar ze kunnen geen tijdgebonden coördinatie uitdrukken zoals "zend pas uit nadat alle drie de bronnen minstens één waarde hebben geproduceerd". Die declaratieve compositie in de tijd is de blijvende reden dat RxJS in de gereedschapskist blijft.
Kern-RxJS-operators waarop elke Angular-ontwikkelaar vertrouwt
Operators zijn pure functies die een Observable aannemen en een nieuwe teruggeven. Het klassieke sollicitatiescenario is zoeken tijdens het typen, omdat het vier operators tegelijk in beweging zet: de invoer afremmen, duplicaten overslaan, verouderde verzoeken annuleren en herstellen van fouten.
import { Component, inject } from '@angular/core';
import { FormControl, ReactiveFormsModule } from '@angular/forms';
import { HttpClient } from '@angular/common/http';
import { debounceTime, distinctUntilChanged, switchMap, catchError } from 'rxjs/operators';
import { of } from 'rxjs';
@Component({
selector: 'app-search',
imports: [ReactiveFormsModule],
template: `<input [formControl]="query" placeholder="Search repositories" />`,
})
export class SearchComponent {
private http = inject(HttpClient);
query = new FormControl('');
results$ = this.query.valueChanges.pipe(
debounceTime(300), // wait until typing pauses for 300ms
distinctUntilChanged(), // ignore emissions that repeat the last value
switchMap((term) => // cancel the in-flight request, start a fresh one
this.http.get(`/api/search?q=${term}`).pipe(
catchError(() => of([])) // recover from a failed request without killing the stream
)
)
);
}Het subtiele detail waar interviewers naar peilen, is waarom switchMap op het buitenste niveau zit terwijl catchError erin genest is. catchError op de binnenste HTTP-Observable plaatsen betekent dat een mislukt verzoek een lege array teruggeeft en de buitenste stroom blijft doorlopen. catchError naar de buitenste pipe verplaatsen zou de hele zoekopdracht na de eerste fout beëindigen en elke volgende toetsaanslag breken. De vier flattening-operators beantwoorden elk een andere vraag over gelijktijdigheid, en de verkeerde kiezen is een van de meest voorkomende oorzaken van race conditions in Angular-apps.
Gebruik switchMap om het vorige binnenste verzoek te annuleren en alleen het nieuwste te behouden (typeahead-zoeken). Gebruik mergeMap om elk binnenste verzoek gelijktijdig uit te voeren (onafhankelijke parallelle uploads). Gebruik concatMap om verzoeken in strikte volgorde in de wachtrij te zetten (sequentiële schrijfacties die niet mogen overlappen). Gebruik exhaustMap om nieuwe invoer te negeren totdat de huidige klaar is (een dubbel aangeklikte verzendknop blokkeren).
Deze keuze goed maken is wat een wankele functie in een voorspelbare verandert. De SharpSkill-module over RxJS-operators oefent deze verschillen met beoordeelde vragen die precies de race conditions reproduceren die elke operator voorkomt.
Subjects en multicasting: BehaviorSubject, ReplaySubject en Subject
Een gewone Observable is unicast: elke subscriber start een nieuwe uitvoering. Een Subject is tegelijk een Observable en een Observer, wat het multicast maakt. Die eigenschap maakt Subjects de standaardmanier om een lichtgewicht state-store of een event-bus binnen een service te bouwen.
De drie varianten verschillen in wat ze aan late subscribers herhalen. Een gewone Subject zendt niets uit het verleden uit, dus een subscriber ziet alleen waarden die binnenkomen nadat hij zich heeft geabonneerd. Een BehaviorSubject bewaart de huidige waarde en herhaalt die onmiddellijk, en daarom heeft het een beginwaarde nodig. Een ReplaySubject buffert een instelbaar aantal eerdere uitzendingen en herhaalt ze allemaal.
import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
@Injectable({ providedIn: 'root' })
export class CartService {
// BehaviorSubject holds the latest value and replays it to new subscribers
private readonly itemsSubject = new BehaviorSubject<string[]>([]);
// expose a read-only stream, never the writable Subject itself
readonly items$ = this.itemsSubject.asObservable();
add(item: string): void {
const current = this.itemsSubject.value; // synchronous access to the last value
this.itemsSubject.next([...current, item]); // emit the next immutable state
}
}Twee gewoonten zijn hier belangrijk. Ten eerste voorkomt het blootstellen van asObservable() in plaats van het Subject dat externe code next() aanroept en de state via de achterdeur muteert. Ten tweede houdt het uitzenden van een nieuwe array-referentie in plaats van in-place muteren de change detection en gelijkheidscontroles voorspelbaar. Dit patroon dateert van vóór Signals en werkt nog steeds goed voor gedeelde, injecteerbare state die meerdere onafhankelijke componenten gebruiken.
Dat gezegd hebbende, een BehaviorSubject dat puur wordt gebruikt om één enkele huidige waarde vast te houden die in templates wordt gelezen, laat zich tegenwoordig vaak beter uitdrukken als een beschrijfbaar Signal, wat de subscription en de asObservable()-ceremonie wegneemt. Het Subject blijft de sterkere keuze wanneer de store zijn uitzendingen ook moet transformeren, debouncen of combineren met andere streams, aangezien die operators geen direct Signal-equivalent hebben. Per situatie tussen beide kiezen, in plaats van overal op één terug te vallen, is een teken van vloeiendheid dat interviewers belonen.
RxJS-Signals-interop met toSignal en toObservable
Het interop-pakket levert twee kernfuncties. toSignal zet een Observable om in een alleen-lezen Signal dat een template rechtstreeks kan gebruiken, en het beheert de levenscyclus van de subscription automatisch. toObservable doet het omgekeerde en verandert een Signal in een Observable, zodat RxJS-operators de wijzigingen ervan kunnen verwerken.
import { Component, signal, inject } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { toSignal, toObservable } from '@angular/core/rxjs-interop';
import { switchMap } from 'rxjs/operators';
@Component({ selector: 'app-dashboard', template: `{{ user()?.name }}` })
export class DashboardComponent {
private http = inject(HttpClient);
// a Signal drives the query; toObservable turns each change into a stream event
readonly userId = signal(1);
private readonly user$ = toObservable(this.userId).pipe(
switchMap((id) => this.http.get<{ name: string }>(`/api/users/${id}`))
);
// toSignal subscribes immediately and unsubscribes on destroy, no manual teardown
readonly user = toSignal(this.user$, { initialValue: null });
}De optie initialValue verdient aandacht. Zonder deze geeft toSignal een Signal terug dat is getypeerd als de waarde of undefined, omdat er nog niets is uitgezonden. initialValue: null doorgeven geeft het template een gedefinieerde beginstaat en een schoner type. Voor synchrone bronnen zoals een BehaviorSubject garandeert requireSync: true dat bij de eerste lezing een waarde beschikbaar is en verwijdert het undefined volledig uit het type. Deze tweerichtingsbrug is wat een codebase in staat stelt Signals stapsgewijs over te nemen zonder elke bestaande Observable-pipeline te herschrijven. De bijbehorende Angular-Signals-sollicitatiemodule behandelt het reactiviteitsmodel diepgaand, en het overzicht van de Signals-features in Angular 18 traceert hoe deze primitieven zijn geëvolueerd.
Klaar om je Angular gesprekken te halen?
Oefen met onze interactieve simulatoren, flashcards en technische tests.
Observables overbruggen naar signal resources met rxResource
Angular 20 promoot rxResource als de declaratieve manier om asynchrone data uit een Observable in signalgebaseerde state te laden. Het houdt laad-, fout- en opgeloste status bij als signals, wat het grootste deel van de handmatige subscription-boekhouding wegneemt die HTTP-aanroepen vroeger vereisten.
import { Component, signal, inject } from '@angular/core';
import { rxResource } from '@angular/core/rxjs-interop';
import { HttpClient } from '@angular/common/http';
@Component({ selector: 'app-products', template: `` })
export class ProductsComponent {
private http = inject(HttpClient);
readonly category = signal('laptops');
// Angular 20 renamed the fields: request -> params and loader -> stream
readonly products = rxResource({
params: () => ({ category: this.category() }),
stream: ({ params }) =>
this.http.get<Product[]>(`/api/products?category=${params.category}`),
});
// products.value(), products.isLoading() and products.error() are all signals
}De hernoeming van request/loader in Angular 19 naar params/stream in Angular 20 is een veelvoorkomende struikelblok, dus het noemen van de huidige veldnamen wijst in een sollicitatie op actuele kennis. Wanneer het category-signal verandert, annuleert rxResource het vorige verzoek en start het een nieuwe stream, wat de semantiek van switchMap gratis meelevert. De rxResource-API-referentie documenteert de volledige statuslevenscyclus.
Geheugenlekken vermijden met takeUntilDestroyed
Elke handmatige subscribe() die zijn component overleeft, lekt geheugen en kan callbacks afvuren op een vernietigde view. De historische oplossing was een takeUntil(this.destroy$)-patroon met een Subject dat in ngOnDestroy werd afgesloten. Angular verving die boilerplate door takeUntilDestroyed, een operator die de subscription koppelt aan de huidige injection context of een expliciete DestroyRef.
import { Component, inject, DestroyRef } from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { interval } from 'rxjs';
@Component({ selector: 'app-live-feed', template: `` })
export class LiveFeedComponent {
private destroyRef = inject(DestroyRef);
constructor() {
interval(1000)
// completes the subscription automatically when the component is destroyed
.pipe(takeUntilDestroyed(this.destroyRef))
.subscribe((tick) => console.log('tick', tick));
}
}Aangeroepen binnen een constructor of een veld-initialisator heeft takeUntilDestroyed() geen argument nodig, omdat het de omringende DestroyRef leest. Elders aangeroepen, zoals binnen een methode, vereist het een expliciet doorgegeven DestroyRef, zoals hierboven getoond. toSignal en rxResource verkiezen vermijdt handmatige subscriptions volledig, wat de schoonste manier is om lekken te ontwijken; wanneer een kale subscription echt nodig is, is takeUntilDestroyed de juiste bewaker.
takeUntilDestroyed() zonder argument aanroepen buiten een injection context werpt een runtime-fout. Abonneren binnen een event handler, een setTimeout of een RxJS-callback valt buiten die context, dus de DestroyRef moet eerder worden vastgelegd (meestal als een geïnjecteerd veld) en expliciet worden doorgegeven. Dit vergeten is de meest voorkomende oorzaak van de fout "takeUntilDestroyed() can only be used within an injection context".
Angular-RxJS-sollicitatievragen die het oefenen waard zijn
Interviewers cirkelen doorgaans rond dezelfde veelzeggende onderwerpen. Deze bondig kunnen beantwoorden scheidt kandidaten die RxJS hebben gebruikt van wie er alleen over heeft gelezen.
- Hot versus cold Observables. Een cold Observable start zijn producer per subscription, dus elke subscriber krijgt een onafhankelijke uitvoering (een nieuw HTTP-verzoek). Een hot Observable deelt één producer over subscribers heen, wat Subjects en
share()creëren. - switchMap versus mergeMap versus concatMap versus exhaustMap.
switchMapannuleert het vorige binnenste Observable (ideaal voor zoeken).mergeMapvoert alle binnenste Observables gelijktijdig uit.concatMapzet ze op volgorde in de wachtrij.exhaustMapnegeert nieuwe invoer terwijl er één loopt (ideaal om dubbele formulierinzendingen te voorkomen). - Hoe geheugenlekken te voorkomen. Verkies
toSignal,rxResourceof deasync-pipe, die zich allemaal automatisch afmelden; gebruik voor handmatige subscriptionstakeUntilDestroyed. - Wanneer een Observable naar een Signal converteren. Grijp naar
toSignalwanneer een template synchroon een waarde nodig heeft en de bron asynchroon is, zodat de change detection de nieuwste waarde kan lezen zonder eenasync-pipe.
Beoordeelde versies hiervan onder tijdsdruk doorwerken is de snelste manier om ze eigen te maken. De Angular-technologiehub groepeert de modules over RxJS, Signals en change detection die direct op deze vragen aansluiten.
Begin met oefenen!
Test je kennis met onze gespreksimulatoren en technische tests.
Conclusie
RxJS en Signals zijn partners in de moderne Angular-stack, geen rivalen. De inzichten die het waard zijn om mee te nemen naar het volgende project of sollicitatiegesprek:
- Gebruik Signals voor synchrone componenten-state en Observables voor asynchrone gebeurtenis-pipelines die operators nodig hebben.
- Grijp naar
switchMapom verouderd werk te annuleren, naarexhaustMapom duplicaten te blokkeren, en houdcatchErrorop het binnenste Observable zodat de buitenste stroom fouten overleeft. - Stel Subject-state bloot via
asObservable()en zend onveranderlijke waarden uit om de change detection voorspelbaar te houden. - Overbrug de twee modellen met
toSignalentoObservable, en geefinitialValueofrequireSyncdoor voor schone types. - Laad asynchrone data declaratief met
rxResourcein Angular 20, met de veldnamenparamsenstreamin gedachten. - Bescherm elke resterende handmatige subscription met
takeUntilDestroyedom lekken te elimineren.
Tags
Delen
Gerelateerde artikelen

Angular 20 in 2026: Resource API, httpResource en sollicitatievragen
Angular 20 introduceert de Resource API en httpResource als signal-gebaseerde alternatieven voor handmatige HttpClient-subscriptions. Deze handleiding behandelt alle drie Resource-varianten, Zod-validatie en veelgestelde sollicitatievragen.

Angular @defer in 2026: Declaratief Lazy Loading voor Snellere Applicaties
Beheers Angular @defer-blokken voor declaratief lazy loading. Diepgaande analyse van triggers, prefetching, incrementele hydratie, SSR-gedrag en performancepatronen uit de praktijk.

Angular 19 sollicitatievragen: Signals, SSR en onmisbare concepten
De meest voorkomende Angular 19 sollicitatievragen: Signals, incrementele hydration, zoneless change detection en nieuwe reactieve API's met codevoorbeelden en verwachte antwoorden.