Angular OnPush: как заставить изменения быть обнаруженными извне? - PullRequest
3 голосов
/ 29 апреля 2019

У меня есть сценарий, где у меня есть два компонента, расположенных рядом друг с другом, ComponentA и ComponentB. Они оба пользуются сервисной службой.

ComponentB содержит кнопку, которая сделает свойство в Service, Service.counter, увеличенным на 1.

ComponentA отображает значение Service.counter.

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

this.cdr.markForCheck();
this.cdr.detectChanges();
this.ar.tick();
this.zone.run(() => {});

Без необходимости вносить изменения в ComponentA, как я могу убедиться, что он всегда показывает правильное значение?

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

1 Ответ

1 голос
/ 29 апреля 2019

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

Компонент имеет связанный вид.Представление ссылается на DOM и является тем, что мы хотим обновлять.Когда вы используете OnPush, вид компонента должен быть помечен как грязный, если состояние компонента изменяется внешне.

Когда вы говорите even from the root component, это означает, что вы пытаетесь пометить неправильный вид как грязный.Если вы хотите увидеть изменения в ComponentA, вам нужно пометить это представление компонента как грязное.

Примерно так.

@Component({...})
public class ComponentA implements OnInit {
    public count; // rendered in the view

    public constructor(private _change: ChangeDetectorRef,
                       private _service: MyService) {
    }

    public onInit() {
         this._service.getCounter().subscribe(value=> {
             this.count = value; // will not update the view.
             this._change.markForCheck(); // tell Angular it's dirty
         });
    }
}

Таким образом, вышеприведенное будет работать в 99% случаев.случаях, но если методы getCounter() возвращают наблюдаемую информацию, которая выполняется вне области действия Angular, и вы должны сделать это явно, потому что асинхронные операции автоматически зонируются, то вы должны использовать метод zone.run().В противном случае, даже если вы отметите вид грязным.Angular не собирается проверять необходимость обновления каких-либо представлений.Этого не должно происходить, если вы не используете неугловые события или явно не используете Angular.

Альтернатива - использовать async трубу, и это более простой подход.

@Component({
    template: `<span>{{count$ | async}}</span>`
})
public class ComponentA implement OnInit {
    public count$: Observable<number>;

    public constructor(private _service: MyService) {
    }

    public onInit() {
        this.count$ = this._service.getCounter();
    }
}

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

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

Тогда вам лучше всего использовать канал async и сделать ваши компоненты реактивными.

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

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