Введение в RxJS
В этом уроке мы разберем базовые принципы RxJS. Эта отдельная библиотека, но в контексте angular устанавливается вместе с ним. RxJS используется во многих Angular аспектах: http клиент, реактивные формы, роутер.
Основной принцип RxJS — реакитвное программирование. В его основе поток данных, а также наблюдаемая сущность и наблюдатели.
Простой пример: вы нажимаете на кнопку «Купить», добавляется товар (поток). Компонент «Корзина» подписывается на изменение (subscribe), и происходит обновление данных (общая сумма и количество товаров).
Простой пример: вы нажимаете на кнопку «Купить», добавляется товар (поток). Компонент «Корзина» подписывается на изменение (subscribe), и происходит обновление данных (общая сумма и количество товаров).
RxJS упрощает работу с асинхронным кодом в сравнении с колбэками и промисами. В уроке мы рассмотрим практические применения RxJS, операторы (очень важная часть работы с потоками) и другие вопросы (например, горячие и холодные observables).
app.ts
import {Component, DestroyRef, inject, OnDestroy, OnInit} from '@angular/core';
import {User, UserService} from './user-service';
import {debounceTime, filter, Observable, of, Subject, Subscription, takeUntil} from 'rxjs';
import {AsyncPipe} from '@angular/common';
import {FormControl, ReactiveFormsModule} from '@angular/forms';
import {takeUntilDestroyed} from '@angular/core/rxjs-interop';
import {UsersList} from './users-list/users-list';
@Component({
selector: 'app-root',
templateUrl: './app.html',
imports: [
ReactiveFormsModule,
AsyncPipe,
UsersList
],
styleUrl: './app.scss'
})
export class App implements OnInit {
protected users: User[] = [];
protected users$!: Observable<User[]>;
protected search = new FormControl<string>('');
protected sub = new Subscription();
protected destroy$!: Subject<any>;
public obs = of(1,2,3);
public subj = new Subject<number>();
protected destroyRef = inject(DestroyRef);
constructor(private userService: UserService) {
}
public ngOnInit() {
this.userService.getUsers().pipe(
takeUntilDestroyed(this.destroyRef)
).subscribe();
this.users$ = this.userService.getUsers();
this.search.valueChanges.pipe(
filter(query => !!query?.trim()),
debounceTime(500),
takeUntilDestroyed(this.destroyRef),
).subscribe()
// this.obs.subscribe(v => console.log('Подписчик первый', v));
// this.obs.subscribe(v => console.log('Подписчик второй', v));
this.subj.subscribe(v => console.log('Подписчик 1', v));
this.subj.next(1);
this.subj.subscribe(v => console.log('Подписчик 2', v));
this.subj.next(2);
}
protected addUser() {
const newUser = this.search.value;
if (newUser) {
const currentUsers = this.userService.users$.getValue();
currentUsers.push(newUser);
this.userService.users$.next(currentUsers);
}
}
}
app.html
<!--<ul>-->
<!-- @for (user of users; track user.id) {-->
<!-- <li>{{user.name}}</li>-->
<!-- }-->
<!--</ul>-->
@let users = users$ | async;
{{users?.length}}
<ul>
@for (user of users; track user.id) {
<li>{{user.name}}</li>
}
</ul>
<input type="text" [formControl]="search">
<button (click)="addUser()">Add user</button>
<div>
<app-users-list></app-users-list>
</div>
user-service.ts
import {inject, Injectable} from '@angular/core';
import { HttpClient } from '@angular/common/http';
import {BehaviorSubject, catchError, forkJoin, filter, fromEvent, map, Observable, of, ReplaySubject, Subject, tap} from 'rxjs';
export interface User {
id: number,
name: string;
username: string;
email: string;
address: Record<string, string>;
phone: string;
website: string;
company: Record<string, string>;
}
@Injectable({
providedIn: 'root',
})
export class UserService {
protected http = inject(HttpClient);
public users$ = new BehaviorSubject<string[]>([]);
getUsers() {
return this.http.get<User[]>('https://jsonplaceholder.typicode.com/users')
.pipe(
map(data => data),
)
}
}
user-list.ts
import {Component, OnInit} from '@angular/core';
import {JsonPipe} from '@angular/common';
import {UserService} from '../user-service';
@Component({
selector: 'app-users-list',
imports: [
JsonPipe
],
templateUrl: './users-list.html',
styleUrl: './users-list.scss',
})
export class UsersList implements OnInit{
protected users: string[] = [];
constructor(private usersService: UserService) {
}
public ngOnInit() {
this.usersService.users$.subscribe(res => this.users = res);
}
}
user-list.html
Users length: {{users | json}}
0 Comments