Извлечение данных с сервера не вызывает обнаружение изменений в дочернем компоненте

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

    this.user = {
      id: 1,
      name: 'John'
    }

    this.http.get('https://api.chucknorris.io/jokes/random')
      .subscribe(joke => this.user.joke = joke);

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

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

Я приложил упрощенную демонстрацию stackblitz.

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


person MTZ    schedule 22.07.2019    source источник
comment
comment
@ AJT_82 хороший ответ. Может быть, добавить предложение, объясняющее, почему код правильный?   -  person Keenan Diggs    schedule 22.07.2019
comment
@ AJT_82 AJT_82 Пожалуйста, не отмечайте мой вопрос как дубликат, пока не объясните мне, почему это так. Я дал вам ссылку на статью, в которой говорится, что ответ на повторяющийся вопрос неверен, если только вы не измените стратегию обнаружения изменений на OnPush. Если я неправильно понял статью, пожалуйста, дайте мне знать. Кстати, я также говорил о стратегии обнаружения изменений в своем вопросе, поэтому я думаю, что это еще одна причина не отмечать вопрос как дубликат.   -  person MTZ    schedule 22.07.2019
comment
Как и повторяющиеся состояния: If you modify the content of an object, Angular won't recognize. Это просто факт. Если бы вы использовали примитивное значение, обнаружение изменений уловило бы это, но здесь мы имеем дело с объектом, и angular не подхватит изменение, пока не изменится ссылка. То же самое было бы, если бы это был массив, и вы изменили бы один объект в массиве, angular не уловил бы этого.   -  person AJT82    schedule 22.07.2019
comment
@ AJT_82 Я прочитал вопрос и понял это. Но это в статье говорится, что whenever some asynchronous operation has been performed, our application state might have changed. Так что, должно быть, кто-то ошибся (парень, который ответил на вопрос о stackoverflow, ИЛИ парень, написавший статью). ИМО, парень, который написал вопрос о стеке, неправ, поэтому я не могу поверить, что If you modify the content of an object, Angular won't recognize. Пожалуйста, дайте мне официальную рекомендацию.   -  person MTZ    schedule 22.07.2019
comment
Я изменил свой код. Как видите, обнаружение изменений выполняется при каждом запросе, но ngOnChanges не вызывается каждый раз.   -  person MTZ    schedule 22.07.2019
comment
Вы изменяете свойство в объекте, но не ссылку. Вот в чем проблема. Я внес некоторые изменения в ваш stackblitz, как и в ссылке, которой вы поделились, этот пользователь меняет ссылку, поэтому angular может увидеть изменение. Посмотрите на эту демонстрацию... мы меняем ссылку на объект с помощью: .subscribe(joke => this.user = joke); ЭТО работает, но когда вы изменяете одно свойство, angular этого не поймает. Модифицированный stackblitz: stackblitz.com/edit/angular- 2avwx4?file=src/app/   -  person AJT82    schedule 22.07.2019
comment
Таким образом, разница в том, что если вы присвоите всему объекту новое значение, обнаружение изменений обнаружит это. Но если вы измените только одно свойство, обнаружение изменений не обнаружит это изменение. Надеюсь, я смог объяснить это понятнее :) Так что на самом деле это не имеет ничего общего с http-запросом. Именно так работает обнаружение угловых изменений.   -  person AJT82    schedule 22.07.2019
comment
Я снова изменил свой код. Как видите, если я добавляю свойство к объекту и отображаю это свойство непосредственно из объекта, оно работает. Вывод: обнаружение изменений срабатывает каждый раз, но ngOnChanges вызывается только в том случае, если ссылки разные. Так что я думаю, что я не заслуживаю повторяющегося тега :)   -  person MTZ    schedule 22.07.2019
comment
Извините, мой stackblitz был неправильным, это тот, который меняет всю ссылку, где мы видим, что ngOnChanges вызывается, поскольку мы меняем ссылку на объект: stackblitz.com/edit/ Вы сами попали в точку. ngOnChanges не срабатывает, пока ссылка не изменится. Это ИМЕННО то, что говорит дубликат. вопрос в том, почему ngOnChanges не запускается, и в ответе говорится, что If if you have a binding to a property of an object or item of an array, Angular will check the binding, but ngOnChanges won't be called   -  person AJT82    schedule 22.07.2019
comment
Да, но проблема была в том, что я думал, что обнаружение изменений имеет отношение один к одному с ngOnChanges, но это не так.   -  person MTZ    schedule 22.07.2019
comment
Я добавил еще пару дубликатов, которые все говорят то же самое;)   -  person AJT82    schedule 22.07.2019
comment
Извините, не понимаю, что вы имеете в виду под: I thought that change detection has a one to one relationship with ngOnChanges   -  person AJT82    schedule 22.07.2019
comment
Я имел в виду, что обнаружение изменений выполняется в любом случае, независимо от ngOnChanges. Если бы это было не так, шутка не отображалась бы в дочернем компоненте при выполнении {{user?.joke?.value}} (здесь)   -  person MTZ    schedule 22.07.2019
comment
Да, обнаружение изменений выполняется. Но ваш вопрос о том, почему ngOnChanges не вызывается.   -  person AJT82    schedule 22.07.2019
comment
На самом деле, название относится к обнаружению изменений, и я неправильно понял упомянутые выше вещи. Однако я должен отредактировать свой вопрос   -  person MTZ    schedule 22.07.2019
comment
Я не знаю, думаете ли вы, что это как-то связано с http-запросом. Это не так. Посмотрите, здесь мы помещаем значение для user.joke через секунду, мы видим, что оно передается дочернему элементу, но ngOnChanges не запускается, так как мы только что изменили свойство. Надеюсь, станет понятнее. Так что это не имеет ничего общего с http, просто как работает обнаружение угловых изменений: stackblitz.com/edit/angular-bkqeq6?file=src/app/child/   -  person AJT82    schedule 23.07.2019


Ответы (1)


Обнаружение угловых изменений не срабатывает, если не обнаруживает новую ссылку.

Если вы перезапишете существующего пользователя вместе с ним и новой опорой, angular обнаружит новую ссылку и обновит ее.

 this.http.get('https://api.chucknorris.io/jokes/random')
      .subscribe(joke => this.user = {...this.user, joke};
person cnps    schedule 22.07.2019
comment
почему минус? - person cnps; 22.07.2019
comment
потому что я уже упоминал Примечание: я знаю, что могу передать копию этого объекта, когда поступят новые данные, но я думаю, что это должен быть лучший подход. И даже так, @AJT_82 уже дал мне этот ответ - person MTZ; 22.07.2019
comment
@MTZ Хорошо, я, честно говоря, этого не заметил. Я все еще думаю, что это лучший подход, если вам действительно не нужна та же ссылка. Вы пробовали с changeDetectorRef? - person cnps; 22.07.2019
comment
Да. Я пробовал. - person MTZ; 22.07.2019