В чем разница между ChangeDetectorRef.markForCheck()
иChangeDetectorRef.detectChanges()
?
Я только нашел информацию на SO о разнице междуNgZone.run()
между этими двумя функциями, но не об этих.
Для ответов со ссылкой только на документ, пожалуйста, проиллюстрируйте некоторые практические сценарии, чтобы выбрать один из других.
angular
angular2-changedetection
парламент
источник
источник
Ответы:
Из документов:
Это означает, что в случае, когда какая-либо вещь внутри вашей модели (вашего класса) изменилась, но она не отражала представление, вам может потребоваться уведомить Angular, чтобы обнаружить эти изменения (обнаружить локальные изменения) и обновить представление.
Возможные сценарии могут быть:
1- Детектор изменений отсоединен от вида (см. Отсоединение )
2- Произошло обновление, но оно не было внутри Angular Zone, поэтому Angular не знает об этом.
Например, когда сторонняя функция обновила вашу модель, и вы хотите обновить представление после этого.
Поскольку этот код находится за пределами зоны Angular (возможно), вам, скорее всего, необходимо убедиться, что обнаружены изменения и обновлено представление, таким образом:
ПРИМЕЧАНИЕ :
Есть и другие способы заставить работать выше, иными словами, есть и другие способы внести это изменение в цикл угловых изменений.
** Вы можете обернуть эту стороннюю функцию внутри zone.run:
** Вы можете обернуть функцию внутри setTimeout:
3. Есть также случаи, когда вы обновляете модель после ее
change detection cycle
завершения, где в этих случаях вы получаете эту страшную ошибку:«Выражение изменилось после того, как оно было проверено»;
Обычно это означает (на языке Angular2):
Я увидел изменение в вашей модели, которое было вызвано одним из моих принятых способов (события, запросы XHR, setTimeout и ...), а затем я запустил обнаружение изменений, чтобы обновить ваше представление, и я завершил его, но затем появился другой функция в вашем коде, которая снова обновила модель, и я не хочу снова запускать обнаружение изменений, потому что больше нет грязной проверки, как AngularJS: D и мы должны использовать односторонний поток данных!
Вы обязательно столкнетесь с этой ошибкой: P.
Несколько способов это исправить:
1- Правильный путь : убедитесь, что обновление находится в цикле обнаружения изменений (обновления Angular2 - это односторонний поток, который происходит один раз, не обновляйте модель после этого и не перемещайте код в лучшее место / время).
2- Ленивый способ : после того, как это обновление запустит detectChanges (), чтобы сделать angular2 счастливым, это определенно не лучший способ, но, как вы спросили, каковы возможные сценарии, это один из них.
Таким образом, вы говорите: я искренне знаю, что вы запустили обнаружение изменений, но я хочу, чтобы вы сделали это снова, потому что мне нужно было что-то обновить на лету после того, как вы закончили проверку.
3- Поместите код внутри
setTimeout
, потому чтоsetTimeout
пропатчен по зонам и будет работатьdetectChanges
после его завершения.Из документов
Это главным образом необходимо, когда ChangeDetectionStrategy вашего компонента - OnPush .
OnPush сам по себе означает, что запускать обнаружение изменений можно только в том случае, если произошло что-то из этого:
1- Один из @inputs компонента был полностью заменен новым значением, или, проще говоря, если ссылка на свойство @Input полностью изменилась.
Итак, если ChangeDetectionStrategy вашего компонента - OnPush, и тогда у вас есть:
И затем вы обновляете / видоизменяете это как:
Это не обновит ссылку на obj , следовательно, обнаружение изменений не будет запущено, поэтому представление не отражает обновление / мутацию.
В этом случае вы должны вручную указать Angular для проверки и обновления представления (markForCheck);
Так что, если вы сделали это:
Вам нужно сделать это:
Скорее, ниже приведёт к запуску обнаружения изменений:
Который полностью заменил предыдущий объект новым
{}
;2- Событие сработало, как щелчок, или что-то подобное, или любой из дочерних компонентов отправил событие.
События как:
Итак, вкратце:
Используйте,
detectChanges()
когда вы обновили модель после того, как angular запустил ее обнаружение изменений, или если обновление вообще не было в angular мире.Используйте,
markForCheck()
если вы используете OnPush и обходите егоChangeDetectionStrategy
, изменяя некоторые данные, или вы обновили модель внутри setTimeout ;источник
detectChanges
Обновление просмотра. Смотрите это подробное объяснение .this.cdMode === ChangeDetectorStatus.Checked
она не будет обновлять представление, поэтому вы должны использовать markForCheck.detectChanges
. И нетcdMode
в Angular4.x.x
. Я пишу об этом в своей статье. Рада что тебе понравилось. Не забывайте, что вы можете порекомендовать его на среднем или подписаться на меня :)Самое большое различие между ними состоит в том, что
detectChanges()
фактически запускает обнаружение изменений, ноmarkForCheck()
не запускает обнаружение изменений.detectChanges
Этот используется для запуска обнаружения изменений для дерева компонентов, начиная с компонента, который вы запускаете
detectChanges()
. Таким образом, обнаружение изменений будет выполняться для текущего компонента и всех его дочерних элементов. Angular содержит ссылки на корневое дерево компонентов вApplicationRef
и, когда происходит какая-либо асинхронная операция, она запускает обнаружение изменений в этом корневом компоненте с помощью метода-оболочкиtick()
:view
Вот представление корневого компонента. Корневых компонентов может быть много, как я описал в разделе « Каковы последствия начальной загрузки нескольких компонентов» .@milad описал причины, по которым вам может понадобиться запускать обнаружение изменений вручную.
markForCheck
Как я уже сказал, этот парень вообще не вызывает обнаружение изменений. Он просто идет вверх от текущего компонента к корневому компоненту и обновляет их состояние просмотра
ChecksEnabled
. Вот исходный код:Фактическое обнаружение изменений для компонента не запланировано, но когда это произойдет в будущем (как часть текущего или следующего цикла CD), будут проверены представления родительского компонента, даже если у них были отсоединенные детекторы изменений. Детекторы изменений могут быть отсоединены с помощью
cd.detach()
или путем указанияOnPush
стратегии обнаружения изменений. Все собственные обработчики событий отмечают все родительские представления компонентов для проверки.Этот подход часто используется в
ngDoCheck
хуке жизненного цикла. Вы можете прочитать больше в разделе Если вы думаете,ngDoCheck
что ваш компонент проверяется - прочитайте эту статью .Смотрите также Все, что вам нужно знать об обнаружении изменений в Angular для получения более подробной информации.
источник
markForCheck
. Так что, если вы не используете асинхронный канал, это, вероятно, то, что вы должны использовать. Однако имейте в виду, что обновление магазина должно происходить в результате некоторого асинхронного события для запуска обнаружения изменений. Это всегда так. Но есть исключения blog.angularindepth.com/…async pipe
так как внутри подписки у нас обычно есть несколько вещей, которые нужно сделать, какcall setFromValues
do some comparison
... и еслиasync
самmarkForCheck
вызов вызывает в чем проблема, если мы сами это называем? но опять же у нас обычно есть 2-3 или иногда больше селекторов вngOnInit
получении различных данных ... и мы вызываем ихmarkForCheck
все ... это нормально?cd.detectChanges()
сразу запустит обнаружение изменений от текущего компонента до его потомков.cd.markForCheck()
не будет запускать обнаружение изменений, но пометит своих предков как нужных для запуска обнаружения изменений. В следующий раз, когда обнаружение изменений будет выполнено где угодно, оно будет работать и для тех компонентов, которые были отмеченыcd.markForCheck()
. Часто изменения затрагивают несколько компонентов, и где-то будет вызвано обнаружение изменений. По сути, вы говорите: давайте просто удостоверимся, что этот компонент также обновляется, когда это происходит. (Представление немедленно обновляется в каждом написанном мной проекте, но не в каждом модульном тесте).cd.detectChanges()
в данный момент не выполняется обнаружение изменений, используйтеcd.markForCheck()
.detectChanges()
будет ошибка в этом случае. Это, вероятно, означает, что вы пытаетесь отредактировать состояние компонента-предка, который работает против предположений, на которые ориентировано обнаружение изменений Angular.detectChanges()
.markForCheck()
может не обновлять ваше мнение вовремя. Модульное тестирование что-то влияет на ваш вид, например, может потребоваться вручную вызвать,fixture.detectChanges()
когда это не было необходимо в самом приложении.detectChanges()
так как вы не запускаете обнаружение изменений на предках компонента без необходимости.источник