Angular Signals dhe RxJS nuk janë kundërshtarë. Ato janë mjete të ndryshme për probleme të ndryshme.
Signals janë shumë të përshtatshme për gjendje aktuale të UI-së, vlera të derivuara dhe store të thjeshta në nivel feature.
RxJS është shumë i përshtatshëm për rrjedha asinkrone, evente në kohë, debounce, anulim kërkesash, retry, polling, WebSocket dhe kombinim të disa burimeve.
Pyetja e saktë nuk është: “A duhet të përdor Signals apo RxJS?”. Pyetja e saktë është: “A po menaxhoj një vlerë aktuale apo një rrjedhë eventesh në kohë?”.
Modeli mendor
Një Signal përfaqëson një vlerë aktuale. Ti e lexon vlerën duke thirrur funksionin, për shembull count().
Një Observable përfaqëson një rrjedhë vlerash në kohë. Ai mund të emetojë shumë vlera, mund të përfundojë, mund të japë error dhe mund të anulohet.
Signals janë më të thjeshta kur gjendja është sinkrone.
RxJS është më i fuqishëm kur koha, eventet dhe asinkronia janë pjesë e problemit.
| Skenari | Zgjedhja më e mirë | Arsyeja |
|---|---|---|
| Menu e hapur ose e mbyllur | Signals | Gjendje lokale shumë e thjeshtë |
| Filtrim lokal i një liste | Signals | Vlerë e derivuar nga gjendja aktuale |
| Kërkim në backend me debounce | RxJS | Ka kohë, vonesë dhe anulim kërkesash |
| Ndryshim parametrash në route | RxJS plus Signals | Route është stream, UI do vlerën aktuale |
| Shporta e blerjeve | Signals | Totalet janë vlera të derivuara |
| Njoftime live | RxJS plus Signals | WebSocket është stream, UI shfaq mesazhin e fundit |
Kur të përdorësh Signals
Përdor Signals kur ke nevojë të ruash dhe të lexosh gjendjen aktuale të aplikacionit ose komponentit.
Shembuj të thjeshtë janë: tab-i aktiv, modalja e hapur, teksti i kërkimit, tema dark/light, lista e produkteve të zgjedhura ose totali i shportës.
import { computed, signal } from '@angular/core';
const quantity = signal(2);
const unitPrice = signal(50);
const total = computed(() => quantity() * unitPrice());
quantity.set(3);
console.log(total()); // 150
Këtu total është vlerë e derivuar. Nuk ka nevojë ta përditësojmë manualisht.
Skenarë të mirë për Signals
- Gjendje lokale e komponentit.
- UI state.
- Filtra lokalë.
- Vlera të derivuara.
- Store të thjeshta për feature.
- Shporta e blerjeve.
- Tema e aplikacionit.
- Gjendje që lexohet shpesh në template.
Kur të përdorësh RxJS
Përdor RxJS kur problemi nuk është thjesht një vlerë aktuale, por një rrjedhë vlerash në kohë.
Një input kërkimi është shembull shumë i mirë. Përdoruesi shkruan, ndalon, shkruan përsëri dhe çdo ndryshim mund të shkaktojë një kërkesë HTTP.
readonly results$ = this.searchControl.valueChanges.pipe(
debounceTime(300),
distinctUntilChanged(),
switchMap((query) => this.api.searchProducts(query))
);
Këtu debounceTime pret pak para se të bëjë kërkesën.
distinctUntilChanged shmang kërkime të panevojshme për të njëjtën vlerë.
switchMap anulon kërkesën e mëparshme kur vjen një vlerë e re.
Skenarë të mirë për RxJS
- Kërkesa HTTP.
- Debounce në input.
- Anulim kërkesash.
- Reactive forms.
- Router params.
- Router events.
- WebSocket.
- Polling.
- Retry pas gabimeve.
- Kombinim i disa stream-eve.
Shembull real: filtrimi lokal i produkteve me Signals
Mendo një faqe e-commerce ku produktet janë ngarkuar një herë dhe përdoruesi i filtron lokalisht.
Në këtë rast Signals janë shumë të përshtatshme, sepse lista e filtruar është thjesht rezultat i gjendjes aktuale.
import { computed, signal } from '@angular/core';
interface Product {
id: number;
name: string;
category: string;
stock: number;
}
const products = signal<Product[]>([]);
const query = signal('');
const onlyAvailable = signal(false);
const filteredProducts = computed(() => {
const q = query().toLowerCase().trim();
return products().filter((product) => {
const matchesQuery = product.name.toLowerCase().includes(q);
const matchesAvailability = !onlyAvailable() || product.stock > 0;
return matchesQuery && matchesAvailability;
});
});
Kodi është i qartë. Gjendja kryesore është signal. Lista e filtruar është computed.
Shembull real: kërkim në server me RxJS
Tani mendo një kërkim ku çdo tekst duhet të dërgohet në backend.
Nëse përdoruesi shkruan shpejt, nuk duam të dërgojmë dhjetë kërkesa të panevojshme.
Duam të presim pak, të marrim vetëm vlerën e fundit dhe të anulojmë kërkesat e vjetra.
readonly results$ = this.searchControl.valueChanges.pipe(
startWith(this.searchControl.value),
map((value) => value.trim()),
debounceTime(300),
distinctUntilChanged(),
switchMap((query) => {
if (query.length < 2) {
return of([]);
}
return this.api.searchProducts(query).pipe(
catchError(() => of([]))
);
})
);
Ky është një rast klasik për RxJS.
Përdorimi i Signals dhe RxJS së bashku
Shpesh zgjidhja më e mirë është kombinimi.
RxJS menaxhon rrjedhën asinkrone.
Signal mban vlerën aktuale që shfaqet në UI.
import { toSignal } from '@angular/core/rxjs-interop';
readonly results = toSignal(this.results$, {
initialValue: [] as Product[]
});
Kjo e bën template-in më të thjeshtë, sepse mund të lexosh results().
Shembull real: faqe detaji me route param
Parametrat e route në Angular janë Observable.
Kërkesa HTTP për produktin është gjithashtu Observable.
Por template ka nevojë vetëm për produktin aktual.
private readonly product$ = this.route.paramMap.pipe(
map((params) => params.get('id')),
distinctUntilChanged(),
switchMap((id) => {
if (!id) {
return of(null);
}
return this.api.getProductById(id).pipe(
catchError(() => of(null))
);
})
);
readonly product = toSignal(this.product$, {
initialValue: null as Product | null
});
Kjo është arkitekturë e pastër: RxJS për stream-in, Signal për gjendjen aktuale.
Gabime të zakonshme
1. Të zëvendësosh RxJS kudo
Signals nuk e bëjnë RxJS të panevojshëm. Për shumë probleme asinkrone, RxJS është ende mjeti më i mirë.
2. Të përdorësh RxJS për çdo gjendje të vogël
Një boolean lokal si isOpen nuk ka nevojë për BehaviorSubject. Një signal është më i thjeshtë.
3. Të vendosësh logjikë komplekse HTTP brenda effect
effect është i dobishëm për side effects, por nuk duhet të zëvendësojë pipeline të qarta RxJS kur duhen debounce, retry ose cancellation.
4. Të konvertosh çdo gjë pa arsye
Nëse një Observable punon mirë me async pipe, nuk është gjithmonë e nevojshme ta kthesh në signal.
Checklist praktike
- A është gjendje aktuale? Përdor Signals.
- A është vlerë e derivuar? Përdor
computed. - A është rrjedhë eventesh në kohë? Përdor RxJS.
- A duhet debounce? Përdor RxJS.
- A duhet anulim kërkesash? Përdor RxJS me
switchMap. - A duhet vetëm vlera e fundit në template? Përdor
toSignal. - A është filtrimi lokal? Signals janë të përshtatshme.
- A është kërkim remote? RxJS është më i përshtatshëm.
- A është WebSocket? RxJS.
- A është shporta me totale? Signals.
- A është form kompleks me valueChanges? RxJS.
- A është UI state i thjeshtë? Signals.
Signals e bëjnë menaxhimin e gjendjes në Angular më të thjeshtë dhe më të lexueshëm.
RxJS mbetet shumë i rëndësishëm për programim asinkron, stream-e, evente në kohë dhe orkestrime komplekse.
Në një aplikacion Angular profesional, përdor Signals për state dhe RxJS për streams.
Kur i kombinon si duhet, kodi bëhet më i pastër, më i mirë për mirëmbajtje dhe më i lehtë për t'u kuptuar nga ekipi.