force detector detectchanges component changedetectorref changedetection change angular angular2-changedetection

angular - detectchanges - changedetectorref ionic



¿Cuál es la diferencia entre markForCheck() y detectChanges() (2)

¿Cuál es la diferencia entre ChangeDetectorRef.markForCheck() y ChangeDetectorRef.detectChanges() ?

Solo encontré información sobre SO en cuanto a la diferencia entre NgZone.run() , pero no entre estas dos funciones.

Para obtener respuestas con solo una referencia al documento, ilustre algunos escenarios prácticos para elegir uno sobre el otro.


De documentos:

detectChanges (): void

Comprueba el detector de cambios y sus elementos secundarios.

Es decir, si hay un caso en el que algo dentro de su modelo (su clase) ha cambiado pero no ha reflejado la vista, es posible que deba notificar a Angular para detectar esos cambios (detectar cambios locales) y actualizar la vista.

Los posibles escenarios pueden ser:

1- El detector de cambio se separa de la vista (ver detach )

2- Ha ocurrido una actualización pero no ha estado dentro de la Zona Angular, por lo tanto, Angular no lo sabe.

Al igual que cuando una función de terceros ha actualizado su modelo y desea actualizar la vista después de eso.

someFunctionThatIsRunByAThirdPartyCode(){ yourModel.text = "new text"; }

Debido a que este código está fuera de la zona de Angular (probablemente), lo más probable es que necesite asegurarse de detectar los cambios y actualizar la vista, por lo tanto:

myFunction(){ someFunctionThatIsRunByAThirdPartyCode(); // Let''s detect the changes that above function made to the model which Angular is not aware of. this.cd.detectChanges(); }

NOTA

Hay otras formas de hacer que el trabajo anterior funcione, en otras palabras, hay otras formas de llevar ese cambio dentro del ciclo de cambio angular.

** Podría incluir esa función de terceros dentro de una zona. Ejecutar:

myFunction(){ this.zone.run(this.someFunctionThatIsRunByAThirdPartyCode); }

** Podría ajustar la función dentro de un setTimeout:

myFunction(){ setTimeout(this.someFunctionThatIsRunByAThirdPartyCode,0); }

3- También hay casos en los que actualiza el modelo después de que finaliza el change detection cycle , donde en esos casos obtiene este temido error:

"La expresión ha cambiado después de que se verificó";

Esto generalmente significa (del lenguaje Angular2):

Vi un cambio en su modelo que fue causado por una de mis formas aceptadas (eventos, solicitudes XHR, setTimeout y ...) y luego ejecuté mi detección de cambios para actualizar su vista y terminé, pero luego hubo otra funciona en su código que actualizó el modelo nuevamente y no quiero volver a ejecutar mi detección de cambios porque ya no hay una verificación sucia como AngularJS: D y deberíamos usar un flujo de datos unidireccional.

Definitivamente te encontrarás con este error: P.

Un par de formas de solucionarlo:

1- Forma adecuada : asegúrese de que la actualización esté dentro del ciclo de detección de cambios (las actualizaciones de Angular2 son unidireccionales que ocurren una vez, no actualice el modelo después de eso y mueva su código a un lugar / hora mejor).

2- Manera perezosa : ejecuta detectChanges () después de esa actualización para hacer feliz a angular2, esta definitivamente no es la mejor manera, pero como preguntaste cuáles son los posibles escenarios, esta es una de ellas.

De esta manera estás diciendo: Sinceramente sé que ejecutaste la detección de cambios, pero quiero que lo vuelvas a hacer porque tuve que actualizar algo sobre la marcha después de que terminaste la comprobación.

3- Ponga el código dentro de un setTimeout , porque setTimeout está parcheado por zona y ejecutará detectChanges después de que haya terminado.

De los documentos

markForCheck() : void

Marca todos los antepasados ​​ChangeDetectionStrategy como para comprobarlos.

Esto se necesita principalmente cuando ChangeDetectionStrategy de su componente es OnPush .

OnPush en sí mismo significa, solo ejecuta la detección de cambios si alguno de estos ha sucedido:

1- Una de las entradas @ del componente se ha reemplazado completamente con un nuevo valor, o simplemente, si la referencia de la propiedad @Input ha cambiado por completo.

Entonces, si ChangeDetectionStrategy de su componente es OnPush y luego tiene:

var obj = { name:''Milad'' };

Y luego lo actualizas / mutas como:

obj.name = "a new name";

Esto no actualizará la referencia obj , por lo tanto, la detección de cambios no se ejecutará, por lo tanto, la vista no refleja la actualización / mutación.

En este caso, debe indicarle manualmente a Angular que verifique y actualice la vista (markForCheck);

Entonces, si hiciste esto:

obj.name = "a new name";

Usted necesita hacer ésto:

this.cd.markForCheck();

Por el contrario, a continuación causaría que se ejecutara una detección de cambio:

obj = { name:"a new name" };

Que reemplazó completamente el obj anterior con un nuevo {} ;

2- Se ha disparado un evento, como un clic o algo así o cualquiera de los componentes secundarios ha emitido un evento.

Eventos como:

  • Hacer clic
  • Tecla Arriba
  • Eventos de suscripción
  • etc.

En resumen:

  • Use detectChanges() cuando haya actualizado el modelo después de que angular haya ejecutado su detección de cambios, o si la actualización no ha estado en el mundo angular.

  • Use markForCheck() si está usando OnPush y está pasando por alto la ChangeDetectionStrategy al mutar algunos datos o ha actualizado el modelo dentro de un setTimeout ;


La mayor diferencia entre los dos es que detectChanges() realidad activa la detección de cambios, mientras que markForCheck() no activa la detección de cambios.

detectChanges

Este se usa para ejecutar la detección de cambios para el árbol de componentes que comienza con el componente en el que se detectChanges() . Por lo tanto, la detección de cambios se ejecutará para el componente actual y todos sus elementos secundarios. Angular contiene referencias al árbol de componentes raíz en ApplicationRef y cuando ocurre cualquier operación asíncrona, activa la detección de cambios en este componente raíz a través de un método de envoltura tick() :

@Injectable() export class ApplicationRef_ extends ApplicationRef { ... tick(): void { if (this._runningTick) { throw new Error(''ApplicationRef.tick is called recursively''); } const scope = ApplicationRef_._tickScope(); try { this._runningTick = true; this._views.forEach((view) => view.detectChanges()); <------------------

view aquí es la vista del componente raíz. Puede haber muchos componentes raíz como describí en ¿Cuáles son las implicaciones de arrancar múltiples componentes ?

@milad describió las razones por las que potencialmente podría necesitar activar la detección de cambios manualmente.

markForCheck

Como dije, este tipo no activa la detección de cambios en absoluto. Simplemente va hacia arriba desde el componente actual al componente raíz y actualiza su estado de vista a ChecksEnabled . Aquí está el código fuente:

export function markParentViewsForCheck(view: ViewData) { let currView: ViewData|null = view; while (currView) { if (currView.def.flags & ViewFlags.OnPush) { currView.state |= ViewState.ChecksEnabled; <----------------- } currView = currView.viewContainerParent || currView.parent; } }

La detección de cambio real para el componente no está programada, pero cuando sucederá en el futuro (ya sea como parte del ciclo de CD actual o siguiente), las vistas del componente principal se verificarán incluso si se han desconectado los detectores de cambio. Los detectores de cambio se pueden separar usando cd.detach() o especificando la estrategia de detección de cambio de OnPush . Todos los controladores de eventos nativos marcan todas las vistas de componentes principales para su verificación.

Este enfoque a menudo se usa en el gancho del ciclo de vida ngDoCheck . Puede leer más en Si cree que ngDoCheck significa que su componente está siendo verificado, lea este artículo .

Consulte también Todo lo que necesita saber sobre la detección de cambios en Angular para obtener más detalles.