Родственный компонент не получает испускаемые изменения

В моем проекте Angular 9 у меня есть 2 компонента, которые являются братьями и сестрами, и parent component. При изменении в component A я испускаю значение, которое устанавливается в parent component и вызывает метод в component B. Метод в component B выдает другое значение, и оно устанавливается в parent component. Изменение при изменении в component A продолжается, но испускаемое значение из component B, установленное в parent component (которое является входом в component A), не изменяется. Я не знаю, почему это не вход для component A не меняется, даже если родитель обновляет значение.

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

setSomeNum(someNum: number) {
    // this is run on someNumberEmitter in Component A
    this.num = someNum;
    if (this.viewChildComponentB) {
        this.viewChildComponentB.remove(someNum);
    }
}
setSomeOtherNum (someOtherNum: number) {
    // this is run on someDiffNumEmitter in Component B
    this.otherNum = someOtherNum
}

Компонент А

componentAOnChange(someNum: number) {
    this.someNumberEmitter.emit(someNum);
    // this.inputFromComponentB is the original value instead of the one emitted in Component B (this.someDiffNum)
    this.someService.applyCalc(someNum, this.inputFromComponentB);
}

Компонент Б

remove(someNum: number) {
    this.someDiffNumEmitter.emit(this.someDiffNum);
    this.someService.applyCalc(someNum, this.someDiffNum);
}

Я использую стратегию обнаружения изменений OnPush, но ничего не изменилось. Как родственный компонент A может работать с изменениями данных из компонента B?


person Vorpal56    schedule 28.08.2020    source источник


Ответы (1)


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

Теперь к вашей проблеме:

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

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

Простое решение, которое мне нравится использовать, — это использовать Subject или BehaviorSubject вместо асинхронного канала. Таким образом, он обеспечивает бесперебойную работу со стратегией обнаружения изменений OnPush, поскольку ChangeDetection будет запускаться, когда Observable выдает новое значение, а канал async позаботится об отмене подписки на Observable за вас.

Если бы я изменил ваши текущие компоненты, это выглядело бы примерно так:

Родитель:

num$ = new Subject<number>();
otherNum$ = new Subject<number>();

setSomeNum(someNum: number) {
    this.num$.next(someNum);
}

setSomeOtherNum (someOtherNum: number) {
    // this is run on someDiffNumEmitter in Component B
    this.otherNum$.next(someOtherNum)
}

Затем в HTML вы можете использовать асинхронный канал, например:

<some-component [num]="num$ | async" [otherNum]="otherNum$ | async"></some-component>

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

И это почти все. Вы должны иметь Subject как Observable, а затем поделиться им с дочерними компонентами, после обновления Observable данные дочерних компонентов также будут обновлены.

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

person Yair Cohen    schedule 28.08.2020