Как правильно обмениваться данными между двумя компонентами, используя rxjs ReplaySubject? - PullRequest
0 голосов
/ 24 января 2019

Я разработал компонент с двумя представлениями. Компонент A имеет контактную форму, а компонент B - это страница «Спасибо».

Компонент А: Вы заполняете форму и отправляете ее. Как только приходит ответ, создается новое значение ReplaySubject. Пользователь будет перенаправлен на компонент B.

Компонент B: Компонент инициализирован. Компонент получает значение от субъекта. Представление отображается и отображает сообщение с благодарностью.

Ответ на HTTP-запрос (возвращается после успешного отправки запроса данных формы):

{
   "status": 200,
   "body": {
              "message": "We have received your request with the card information below and it will take 48h to be processed. Thank you!",
              "card": {
                    "name": "John Doe",
                    "email": "john.doe@gmail.com",
                    "accountNumber": "12345-67890"
              }
            },
   "type": "ItemCreated"
}

Код компонента A (форма):

import { Component } from '@angular/core';
import { FormBuilder, Validators } from '@angular/forms';
import { RequestCardWidgetService } from './request-card-widget.service';
import { RouterService } from '@framework/foundation/core';
import { Item } from '@pt/request-card-data'

@Component({
  selector: 'pt-request-card-form',
  templateUrl: './request-card-form.template.html',
  providers: [RouterService]
})
export class RequestCardFormComponent {
  constructor(private fb: FormBuilder, private data: RequestCardWidgetService, private router: RouterService){}

  item: Item = {
    name: '',
    email: '',
    accountNumber: ''
  };

  requestCardForm = this.fb.group({
    name: ['', Validators.required],
    email: ['', Validators.email],
    accountNumber: ['', Validators.required]
  })

  onSubmit() {
    this.item = this.requestCardForm.value;
    this.data.requestCard(this.item)
      .subscribe(data => {
        this.data.processResult(data);
        this.router.navigate(['/success']);
      });
  }

}

Код компонента B (страница «Спасибо»):

import { Component } from '@angular/core';
import { RequestCardWidgetService } from './request-card-widget.service';

@Component({
  selector: 'pt-request-card-success',
  templateUrl: './request-card-success.template.html'
})
export class RequestCardSuccessComponent {
  messages: any; // TODO: To use the proper type...

  constructor( private requestCardService: RequestCardWidgetService) {
    this.messages = this.requestCardService.message;
  }
}

Шаблон компонента B (страница «Спасибо»):

<div *ngIf='(messages | async) as msg'>
  {{ msg.message}}
</div>

Код компонента обслуживания:

import { Injectable } from '@angular/core';
import { HttpResponse } from '@angular/common/http';

import { Observable, ReplaySubject } from 'rxjs';
import { map, take } from 'rxjs/operators';

import {
  RequestCardDataService,
  Item,
  ItemCreated
} from '@example/request-card-data';

@Injectable()
export class RequestCardWidgetService {

  constructor(private dataService: RequestCardDataService) { }

  private readonly results = new ReplaySubject<ItemCreated>();

  readonly message: Observable<ItemCreated> = this.results; // Message Line. This is the variable that I'm rendering in the template. Is this the correct way of extracting subject values?

  requestCard (card: Item): Observable<ItemCreated> {
    return this.dataService.postCardRecord(card).pipe(
      take(1),
      map((response: HttpResponse<ItemCreated>): ItemCreated | {} => {
        return response.body
          ? response.body
          : {};
      })
    );
  }

  processResult(data: ItemCreated) {
    this.results.next(data);
  }

}

Резюме: Компонент А имеет форму. После отправки формы результаты сохраняются как новое значение в теме. Пользователь перенаправляется на страницу благодарности. Компонент страницы с благодарностью отображает элемент и получает новейшее значение от темы. Затем он отображает содержимое.

Этот код работает, но у меня есть несколько вопросов.

Вопрос: Это правильный способ использования субъекта?

Это:

readonly message: Observable<ItemCreated> = this.results;

правильный способ извлечения значений из предмета? (Я передаю «сообщение» представлению.)

Есть ли лучшие способы достижения того же результата? Заранее большое спасибо.

1 Ответ

0 голосов
/ 24 января 2019

Это правильный способ использования темы?

ReplaySubect без ограничений воспроизведет все значения, которые он ранее выдал новым подписчикам.Это может привести к ситуациям, когда пользователь может получать ранее отправленные сообщения, пока он, наконец, не получит текущее сообщение.Поэтому, либо ограничьте предмет или рассмотрите использование BehaviorSubject вместо этого.

Извлечение значений из субъекта

A Subject и всех его производных равно Observable с и Observer с.При предоставлении субъекта потребителю вы не хотите показывать интерфейс Observer, т. Е. Потребитель никогда не должен вызывать next, error или complete.Таким образом, как предлагается в комментарии, вы должны убедиться, что вы только предоставляете интерфейс Observable потребителям, сначала вызвав метод asObservable.

readonly message: Observable<ItemCreated> = this.results.asObservable();

Следующие шаги

Если вы хотите продолжить использовать основанную на обслуживании связь между компонентами, то я думаю, что у вас есть возможность очистить / уточнить свой код в соответствии с документами, указанными в комментариях к вопросу.

Если ваше приложение собираетсяусложняясь, я бы понизил архитектуру в стиле Redux и рассмотрел NgRx и, в частности, использование эффектов для управления побочными эффектами.

Эффекты могут удовлетворить все ваши требования благодаряпростые, незаметные наблюдаемые конструкции, то есть эффект для обработки отправки формы, получают ответ и даже переходят на страницу успеха. Более подробную информацию об эффектах можно найти здесь .

Архитектура с избыточностью может быть излишней для простых задач, но если вы работаете с большим приложением, управляющим большим деревом состояний, я предпочитаю этоподход к сервисным интеграциям.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...