<link rel="stylesheet" href="/assets/fonts/jetbrains-mono/jetbrains-mono.css" />
All posts

Angular Signals dhe RXJS

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.


Risorse ufficiali / Official resources / Burime zyrtare

Copy

💬 Shënime nga lexuesit

0 shënime

Shkruaj një shënim

Ndaj mendimin tënd, një sugjerim ose një kompliment

Shënimet e fundit

Ende asnjë shënim. Bëhu i pari që komenton!