Как совместить разбиение на страницы с Obersables и AsyncPipe в Angular 9? - PullRequest
3 голосов
/ 29 мая 2020

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

<ul>
  <li *ngFor="let product of products$ | async">{{ product.name }}</li>
</ul>

<button type="button" (click)="gotoPage(1)">1</button>
<button type="button" (click)="gotoPage(2)">2</button>

Компонент действительно выглядит так:

export class ProductsComponent implements OnInit {
  products$: Observable<Product[]>;

  constructor(
    private service: ProductService
  ) { }

  ngOnInit() {
    this.products$ = this.service.getAll({page: 1});
  }

  gotoPage(page: number): void {
    this.products$ = this.service.getAll({page: page});
  }
}

Мои вопросы: Правильный ли способ обновления Obersavble? Или это приводит к утечкам памяти?

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

Ответы [ 4 ]

1 голос
/ 29 мая 2020

Вы даже не подписываетесь на свой наблюдаемый объект, поэтому я не думаю, что здесь возможна утечка памяти, вы просто получаете некоторые данные, и конвейер asyn c обрабатывает «преобразование» за вас.

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

ngUnsubscribe = new Subject();
myObservable: Observable<any>;

ngOnInit(){
  this.myObservable.pipe(takeUntil(ngUnsubscribe))
  .subscribe(...)
}

ngOnDestroy() {
  this.ngUnsubscribe.next();
  this.ngUnsubscribe.complete();
}

Тема, которая позволит вам инициировать правильную отмену подписки для каждой подписки, имеющей takeUntil.

.next и .complete необходимы, потому что .unsubscribe не работает должным образом (заметил это при работе с NGRX и нашел некоторый поток stackoverflow, который говорит об этом).

1 голос
/ 29 мая 2020

Глядя на источник канала Asyn c, вы можете увидеть внутри transform() функцию:

if (obj !== this._obj) {
  this._dispose();
  return this.transform(obj as any);
}

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

0 голосов
/ 29 мая 2020

Как мы все знаем, на странице также есть количество элементов на странице.

Я предпочитаю изменить критерии на предмет поведения и объединить два наблюдаемых с mergeMap

class ProductService {
  constructor() {
    this.defaultCriteria = {
      page: 0,
      pageSize: 5
    }
  }

  getAll(criteria) {
    criteria = {
      ...this.defaultCriteria,
      ...criteria
    }

    return rxjs.of(Array(criteria.pageSize).fill(0).map((pr, index) => {
      const num = index + criteria.pageSize * criteria.page + 1;
      return {
        id: num,
        name: `Product ${num}`
      }
    }))
  }

}

class ProductsComponent {
  constructor(service) {
    this.service = service;
    this.page$ = new rxjs.BehaviorSubject(0);
    this.products$ = null;
  }

  ngOnInit() {
    this.products$ = this.page$.asObservable()
      .pipe(rxjs.operators.mergeMap(page => this.service.getAll({
        page
      })))
  }

  gotoPage(page) {
    this.page$.next(page);
  }
}

const service = new ProductService();
const component = new ProductsComponent(service);
component.ngOnInit();
component.products$.subscribe(products => console.log(products));
component.gotoPage(1);
component.gotoPage(2);
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.5.5/rxjs.umd.js"></script>
0 голосов
/ 29 мая 2020

Вы всегда можете предотвратить утечку памяти с помощью шаблона takeUntil + ngOnDestroy.

Например,

объявить новую переменную private onDestroy$: Subject<void> = new Subject<void>();

this.service.getAll({page: page})
.pipe(takeUntil(this.onDestroy$))
.subscribe(... do the necessary ...);

И позже, в хук жизненного цикла onDestroy (), вы можете реализовать следующее:

 public ngOnDestroy(): void {
   this.onDestroy$.next();
   this.onDestroy$.complete() 
 }

Фактически мы объявили новую наблюдаемую; Затем, используя метод pipe с takeUntil, мы сообщаем компилятору, что мы хотим отказаться от подписки на наблюдаемый, когда какое-либо значение появляется в onDestroy $. Затем, используя метод pipe с takeUntil, мы сообщаем компилятору, что мы хотим отписаться от наблюдаемого, когда появляется какое-либо значение. в onDestroy $, тем самым предотвращая утечки памяти.

...