ngOnChanges не вызывается, но представление обновляется правильно

У меня вопрос по следующему коду:

Ребенок

export class ChildComponent implements OnChanges {
    public @Input() data: string[];

    ngOnChanges(changes: SimpleChanges) {
        console.log('I am here');
    }
}

Дочерний шаблон

{{ data | json }} // This is not necessary. The behaviour is the same with or without it.

<div *ngFor="let item of data">
    {{ item }}
</div>

Родитель

export class AppComponent implements OnInit {
    public test: string[] = ['hello'];

    ngOnInit() {
        console.log('I am here');
    }

    public addItem() {
        this.test.push('sample');
    }
}

Родительский шаблон

<child-component [data]="test"></child-component>
<button (click)="addItem()">Add</button>

Я понимаю, что ngOnChanges будет вызываться только при изменении ссылки на массив, и если я вставлю элемент в массив, он не будет вызываться. Мое внимание привлекает следующее. Когда я нажимаю кнопку добавления, в массив добавляется новый элемент, и представление обновляется правильно. Я использую канал json и ngFor, чтобы доказать, что он обновляется правильно. Если я не использую json pipe, поведение будет таким же. Итак, если представление обновляется правильно, почему не вызывается ngOnChanges? Кто отвечает за обнаружение изменений для отображения в представлении?

Таким образом, сомнения заключаются в следующем. Почему при добавлении элемента в массив представление обновляется правильно, но почему ngOnChanges не вызывается?

Обнаружение изменений делается по другому?


person Mr. Mars    schedule 04.03.2020    source источник


Ответы (1)


Как Вам, наверное, хорошо известно, ngOnChanges предназначен для обработки любых изменений в @Input() свойствах (в случае, если простая подача новых данных в компонент может иметь некоторые дополнительные эффекты и не может быть выполнена путем объединения set и @Input()). Так что он ориентирован только на @Input() изменений. Также, как Вам хорошо известно, это будет обновляться только в том случае, если ссылка скоро изменится.

И ваш компонент все равно обновляется, потому что:

  • Вы не говорите компоненту использовать только OnPush стратегию обнаружения изменений (так что он будет меняться не только при этих ссылочных изменениях любых @Input() или любых наблюдаемых / событий)
  • и вдобавок (что является ключевым моментом) у вас есть канал inpure внутри вашего дочернего представления. Здесь я нашел вопрос о грязных трубах и, думаю, должен ответить на ваш вопрос: ссылка (поскольку json труба нечистая - docs). Попробуйте удалить его и посмотрите, что будет.

Пожалуйста, примите тот факт, что это всего лишь теория. Но я совершенно уверен, что это правильно.

Изменить: о, и похоже, что есть прекрасный пример этого в официальных документах здесь < / а>:

... летающие герои отображают обновления по мере добавления героев, даже если вы изменяете массив героев.

person Eatos    schedule 04.03.2020
comment
Спасибо за Ваш ответ. Одна вещь, я думаю, что последняя ссылка неверна, так как ведет к документации Json Pipe. Не могли бы вы поделиться правильной ссылкой? :) В связи с этим, даже если вы удалите канал json, ngFor работает правильно, то есть обновляет информацию в представлении. То же самое с json pipe или без него. Итак, обнаружено ли больше изменений в представлении, чем в @Input (ngOnChanges)? Заранее спасибо. - person Mr. Mars; 04.03.2020
comment
Да, извините, ссылка обновлена. Что касается проблемы, я создал пример но, честно говоря, я не знаю ответа. Я думал, что это произошло из-за изменения вида срабатывания трубы. Может, найду что-нибудь, но это предел моих знаний. - person Eatos; 05.03.2020
comment
Angular также ищет изменения в значениях, привязанных к данным. Это то, что мы знаем. Я предполагаю, что Angular обновляет представление, потому что некоторые из его значений привязки изменились, поэтому, возможно, он достаточно резок, чтобы интерполировать *ngFor как набор отдельных привязок {{ data[0] }}, _3 _, ... (как я пытался в примере). Я нашел только это и это. - person Eatos; 05.03.2020