Канал передачи данных между сервисом и компонентом: Subject и BehaviorSubject - необходимо пояснение - PullRequest
0 голосов
/ 24 марта 2020

Я новичок в Angular и застрял в концепции Subject и BehaviorSubject. Кто-нибудь может попытаться объяснить мне? Я искал по сети, но я не могу понять, как это действительно работает. Я также нашел Observable и Observer, но не могу понять принцип.

Я понял, что сервисы используются для хранения глобальных логик c для нескольких компонентов (например, для взаимодействия с API), в то время как component.ts хранить только выделенную логику c.

. Например, я пытаюсь создать приложение погоды с:

  • weather.service.ts, в котором я получаю запрос к API, и где я делаю свою обработку, чтобы возвратить Массив объекта Weather (выделенный класс).
  • Weather.model.ts, где я описываю класс Weather.
  • search.component .ts, который является компонентом.

Я передал свои данные из weather.service.ts в search.component.ts с помощью Observable, я не знаю, насколько это хороший способ.

weather.service.ts

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { Weather } from '../models/Weather.model';

@Injectable({
  providedIn: 'root'
})
export class WeatherService {

  APIKEY: string = "&appid=...";
  URI: string = "https://api.openweathermap.org/data/2.5/forecast?q=";

  constructor(private httpClient: HttpClient) { }

  getWeather(city): Observable<Weather[]> {
    //Cherche une ville dans l'API :
    return this.httpClient.get(this.URI + city + this.APIKEY).pipe(map(
      (data: any) => {
        var weatherArray: Array<Weather> = [];
        for (var i = 0; i < data.list.length; i++) {
          weatherArray.push(new Weather(
            data.list[i].dt,
            data.list[i].main.temp,
            data.list[i].main.temp_min,
            data.list[i].main.temp_max,
            data.list[i].main.feels_like,
            data.list[i].main.pressure,
            data.list[i].main.humidity,
            data.list[i].weather[0].main,
            data.list[i].weather[0].icon,
            data.list[i].clouds.all,
            data.list[i].wind.speed,
            data.list[i].wind.deg
          ));
        }
        return weatherArray;
      }
    ));
  }

}

Weather.model.ts

export class Weather {

    date: Date;
    temp: number;
    tempMin: number;
    tempMax: number;
    tempFelt: number;
    pressure: number;
    humidity: number;
    weatherDesc: string;
    weatherIcon: string;
    clouds: number;
    windSpeed: number;
    windOrientation: number;

    constructor(date: Date,
                temp: number,
                tempMin: number,
                tempMax: number,
                tempFelt: number,
                pressure: number,
                humidity: number,
                weatherDesc: string,
                weatherIcon: string,
                clouds: number,
                windSpeed: number,
                windOrientation: number) {

    }
}

search.component.ts

import { Component, OnInit } from '@angular/core';
import { Router, ActivatedRoute } from '@angular/router';
import { WeatherService } from 'src/app/services/weather.service';
import { Observable } from 'rxjs';
import { Weather } from '../../models/Weather.model';

@Component({
  selector: 'app-search',
  templateUrl: './search.component.html',
  styleUrls: ['./search.component.scss']
})
export class SearchComponent implements OnInit {

  searchedCity: string;
  weatherItems: Array<Weather>;

  constructor(private router: Router,
              private route: ActivatedRoute,
              private weatherService: WeatherService) { }

  ngOnInit(): void {
    //On récupère la ville si elle y est :
    if (this.route.snapshot.params['city']) {
      this.searchedCity = this.route.snapshot.params['city'];
      this.weatherService.getWeather(this.searchedCity).subscribe(
        (data) => {
          this.weatherItems = data;
        }, (err) => {
          console.log(err);
        });
    } 
  }

}

1 Ответ

0 голосов
/ 24 марта 2020

Ваш код правильный, и в этом случае нет необходимости использовать BehaviorSubject или Subject.

Для лучшего понимания различий см. https://coryrylan.com/blog/rxjs-observables-versus-subjects

Но вкратце, это Наблюдаемый, и наблюдатель

import { Observable } from 'rxjs';

const observable = new Observable(observer => {
  setTimeout(() => observer.next('hello from Observable!'), 1000);
});

observable.subscribe(v => console.log(v));

и Субъекты наследуются от Наблюдаемой и имеют вид

import { Subject } from 'rxjs';

const subject = new Subject();

subject.next('missed message from Subject');

subject.subscribe(v => console.log(v));

subject.next('hello from subject!');

обратите внимание, что вы можете назвать next на предмете, (вам нужно сделать то же самое с помощью обозревателя в наблюдаемом)

также до сих пор вы не можете получить доступ к последнему предоставленному значению, поэтому BehaviorSubject для этого, он унаследован от Subject и имеет значение, также время, когда вы создаете его экземпляр, выдаст первое значение в конструкторе

import { ReplaySubject } from 'rxjs';

const behaviorSubject = new BehaviorSubject(
  'hello initial value from BehaviorSubject'
);

behaviorSubject.subscribe(v => console.log(v));

behaviorSubject.next('hello again from BehaviorSubject');

И Subject, и BehaviorSubject имеет complete меню для завершения подписки.

также время, когда вы подписаться на BehaviorSubject он будет выдавать последнее значение.

Улучшение кода

относительно вашего кода есть некоторые улучшения, как показано ниже

weather.model.ts

export interface Weather {

    date: Date;
    temp: number;
    tempMin: number;
    tempMax: number;
    tempFelt: number;
    pressure: number;
    humidity: number;
    weatherDesc: string;
    weatherIcon: string;
    clouds: number;
    windSpeed: number;
    windOrientation: number;

}

сервис

getWeather(city): Observable<Weather[]> {
    return this.httpClient.get(`${this.URI}${city}${this.APIKEY}`)
      .pipe(
         map((data: any) => data.list.map(item => ({
            date: item.dt,
            temp: item.main.temp,
            tempMin: item.main.temp_min,
            tempMax: item.main.temp_max,
            tempFelt: item.main.feels_like,
            pressure: item.main.pressure,
            humidity: item.main.humidity,
            weatherDesc: item.weather[0].main,
            weatherIcon: item.weather[0].icon,
            clouds: item.clouds.all,
            windSpeed: item.wind.speed,
            windOrientation: item.wind.deg
         }))
    );
  }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...