Поведение при обнаружении нечетных изменений Angular 2+ - PullRequest
0 голосов
/ 27 января 2019

Здравствуйте, я работаю над большим приложением, и у меня возникли некоторые проблемы с обнаружением изменений.Я постараюсь объяснить мои настройки как можно лучше.

Родительский компонент ts:

Использование changeDetection: ChangeDetectionStrategy.OnPush

У меня есть переменная, котораянаблюдаемая

loaderOverlay$: Observable<boolean>;

this.loaderOverlay$ = this.store.pipe(
  select(selectors.loaderOverlaySelector)
);

Эта переменная обновляется в результате действия rxjs дочернего компонента.Затем проходит процесс rxjs.(Действие -> Редуктор -> Селектор)

Родительский компонент HTML

<div *ngif="(loaderOverlay$ | async)"></div>

Дочерний компонент № 1 (где я отправляю мое действие):

myFunction() {
  this.store.dispatch(new actions.LoaderOverlay(true));
}

Моя проблема в том, что как только я отправляю действие, *ngif очень шатко.Кажется, он работает не так, как я хочу (отправьте действие, измените значение на true, чтобы появился div).Это очень странно, потому что если я console.log(action.payload) в редукторе, значение фактически обновляется, но *ngif не работает.И что еще более странно, когда я наводю курсор мыши на какой-то другой компонент, кажется, что он срабатывает.

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

ngAfterViewChecked(){
   this.changeDetector.detectChanges();
}

Кажется, это работает для меня.Моя проблема с этим заключается в том, что ngAfterViewChecked запускается огромное количество раз, и я боюсь проблем с производительностью.

Кто-нибудь сталкивался с этой проблемой раньше?Или у кого-нибудь есть предложения относительно того, что происходит и что я могу сделать, чтобы решить эту странную проблему?

Спасибо!

Ответы [ 3 ]

0 голосов
/ 04 февраля 2019

У меня была похожая проблема.При редактировании поля ввода результаты должны были быть получены из бэкэнда и отображены в виде списка.Список не обновлялся, пока я не завис или не щелкнул где-то еще.

Я исправил его, добавив обнаружение изменений вручную после извлечения данных из бэкэнда.

constructor(private cd: ChangeDetectorRef) {}

fetchData.subscribe(results => {
   AddResultsToStore(results);
   this.cd.detectChanges();
});
0 голосов
/ 04 февраля 2019

Ваше значение loaderOverlay$ соответствует значению true? Я создал похожий код (как вы описали) для stackblitz, и я не могу воспроизвести ошибку, с которой вы столкнулись. Это либо ошибка, которая была исправлена ​​в angular / ngrx, либо значение, которое вы выводите, не оценивается как true (выборка не подходит и возвращает неопределенное значение или что-то в этом роде). Попробуйте нажать на наблюдаемое и записать результаты.

https://stackblitz.com/edit/angular-ngrx-update?file=src/app/app.component.css

Позже Редактировать:

Как указал Кристиан Трейна в комментариях, markForCheck (изнутри асинхронного канала) не запускает обнаружение изменений, когда оно вызывается извне. В качестве исправления вы можете использовать планировщик зон в своем канале или определить, откуда происходит изменение, и исправить эту область, чтобы активировать обнаружение изменений внутри угла (поскольку в других областях вашего приложения могут быть проблемы).

https://www.npmjs.com/package/ngx-zone-scheduler?activeTab=readme

public constructor(
  @Inject(ZoneScheduler)
  private readonly zoneScheduler: SchedulerLike,
) {}

this.loaderOverlay$ = this.store.pipe(
  select(selectors.loaderOverlaySelector),
  observeOn(this.zoneScheduler),
);

или вы можете просто tick appRef

public constructor(
  private appRef: ApplicationRef,
) {}

this.loaderOverlay$ = this.store.pipe(
  select(selectors.loaderOverlaySelector),
  tap(_ => this.appRef.tick()),
);
0 голосов
/ 29 января 2019

Из вашего примера кажется, что стратегия onPush используется неправильно.Стратегия onPush означает, что компонент не обязательно будет обновляться, если его @inputs не изменяется, даже если переменные обновляются в компоненте.Из того, что я могу собрать в вашем примере, ссылки @input родительского компонента не меняются, что означает, что обнаружение изменений происходит не так, как вы ожидаете.

Чтобы это исправить, я бы предложил обновить родительский компонент (который подписывается на обновления магазина) либо использовать defaultStrategy, либо вручную вызывать markForCheck(), чтобы запустить обновление.

...