Kurs Angular · Moduł 7: RxJS
Subjects - Wielokierunkowa Komunikacja
W tej lekcji2
Subjects to specjalne Observable, które mogą zarówno emitować jak i odbierać wartości - jak centrum dowodzenia ninja.
Typy Subjects
import { Subject, BehaviorSubject, ReplaySubject, AsyncSubject } from 'rxjs';
// Subject - podstawowy, bez pamięci
const subject = new Subject<string>();
subject.subscribe(v => console.log('A:', v));
subject.next('Hello'); // A: Hello
subject.subscribe(v => console.log('B:', v));
subject.next('World'); // A: World, B: World
// B nie otrzymał 'Hello' - nie było subskrypcji
// BehaviorSubject - pamięta ostatnią wartość
const behavior = new BehaviorSubject<number>(0); // Wymaga wartości początkowej
behavior.subscribe(v => console.log('A:', v)); // A: 0 (od razu!)
behavior.next(1); // A: 1
behavior.subscribe(v => console.log('B:', v)); // B: 1 (ostatnia wartość!)
behavior.next(2); // A: 2, B: 2
// ReplaySubject - pamięta n ostatnich wartości
const replay = new ReplaySubject<number>(2); // Pamięta 2 ostatnie
replay.next(1);
replay.next(2);
replay.next(3);
replay.subscribe(v => console.log(v)); // 2, 3 (ostatnie 2)
// AsyncSubject - emituje tylko ostatnią przy complete
const async = new AsyncSubject<number>();
async.next(1);
async.next(2);
async.subscribe(v => console.log(v)); // Nic
async.next(3);
async.complete(); // Teraz: 3Praktyczny przykład - Serwis Stanu
@Injectable({ providedIn: 'root' })
export class NotificationService {
private notificationsSubject = new BehaviorSubject<Notification[]>([]);
// Wystawiamy tylko Observable (readonly)
readonly notifications$ = this.notificationsSubject.asObservable();
// Bieżąca wartość dostępna synchronicznie
get currentNotifications(): Notification[] {
return this.notificationsSubject.getValue();
}
addNotification(notification: Notification): void {
const current = this.currentNotifications;
this.notificationsSubject.next([...current, notification]);
}
removeNotification(id: number): void {
const filtered = this.currentNotifications.filter(n => n.id !== id);
this.notificationsSubject.next(filtered);
}
clearAll(): void {
this.notificationsSubject.next([]);
}
}
// Użycie w komponencie
@Component({
template: `
@for (notification of notifications$ | async; track notification.id) {
<div class="notification" (click)="remove(notification.id)">
{{ notification.message }}
</div>
}
`
})
export class NotificationListComponent {
notifications$ = inject(NotificationService).notifications$;
private notificationService = inject(NotificationService);
remove(id: number): void {
this.notificationService.removeNotification(id);
}
}Hasła z dokumentacji w tej lekcji
Widzisz błąd w tej lekcji?
Sprawdź się
Odpowiedz na pytania z tej lekcji. Wybierz odpowiedź, a od razu zobaczysz, czy jest poprawna.
1. Czym różni się BehaviorSubject od zwykłego Subject?
2. Co charakteryzuje ReplaySubject?
To 2 z 4 pytań do tej lekcji. Pozostałe rozwiążesz w grze.
Zadania praktyczne w grze
- Edytor kodu
Uzupełnij serwis stanu użytkownika: potrzebny jest Subject z wartością początkową, który pamięta ostatnią wartość i oddaje ją przez getValue().
- Układanie w poziomie
Ułóż tworzenie BehaviorSubject z wartością początkową 0:
- Układanie w pionie
Ułóż linie metody dodającej powiadomienie do serwisu opartego na BehaviorSubject: