strategy que observables example ejemplo change javascript angular

javascript - que - observables angular 5



ChangeDetectionStrategy.OnPush y Observable.suscribirse en Angular 2 (3)

Estoy tratando de ChangeDetectionStrategy.OnPush mejores prácticas cuando uso Observables junto con ChangeDetectionStrategy.OnPush .

El ejemplo demuestra el escenario común de querer mostrar algún tipo de mensaje de carga (o una animación de hilandero simple, tal vez):

Plnkr aquí

@Component({ selector: ''my-app'', template: `Are we loading?: {{loadingMessage}}`, // Obviously "Default" will notice the change in `loadingMessage`... // changeDetection: ChangeDetectionStrategy.Default // But what is best practice when using OnPush? changeDetection: ChangeDetectionStrategy.OnPush }) export class App implements OnInit { private loadingMessage = "Wait for it..."; constructor() { } ngOnInit() { // Pretend we''re loading data from a service. // This component is only interested in the call''s success Observable.of(true) .delay(2000) .subscribe(success => { if(success){ console.log(''Pretend loading: success!''); // OnPush won''t detect this change this.loadingMessage = ''Success!''; } }); } }

Comprendo más o menos el requisito de inmutabilidad con OnPush y, al menos para mí, tiene sentido cuando se habla de datos reales del modelo (probablemente guardados en algún tipo de tienda).

Entonces, tengo dos preguntas:

  1. ¿Por qué la asignación del nuevo valor de cadena ''Success!'' activar el detector de cambio? En lo que respecta a la inmutabilidad, el valor ha cambiado, ¿verdad?
  2. ¿Cómo debe implementarse el componente interno liviano (es decir, loadingMessage ) al usar ChangeDetectionStrategy.OnPush ? Si hay varias prácticas recomendadas, indíqueme la dirección correcta.

AFAIK, OnPush se usa cuando se trabaja directamente con observables :

//our root app component import {Component, OnInit, ChangeDetectionStrategy} from ''angular2/core'' import {Observable} from ''rxjs/Observable''; import ''rxjs/Rx''; @Component({ selector: ''my-app'', template: `Are we loading?: {{ loadingMessage |async }}`, changeDetection: ChangeDetectionStrategy.OnPush }) export class App implements OnInit { private loadingMessage; constructor() { } ngOnInit() { this.loadingMessage = Observable.of(true) .delay(2000) } }


Buena pregunta. Tengo dos citas de Savkin sobre onPush (ya que los documentos de Angular.io todavía no parecen tener información sobre este tema):

El marco verificará los componentes de OnPush solo cuando cambien sus entradas o las plantillas de los componentes emitan eventos. - ref

Al usar OnPush , Angular solo verificará el componente cuando cualquiera de sus propiedades de entrada cambie, cuando se active un evento o cuando un observable active un evento. - ref (en un comentario, respuesta a @vivainio)

La segunda cita parece más completa. (Lástima que fue enterrado en un comentario!)

¿Por qué la asignación del nuevo valor de cadena no es Success! activar el detector de cambio? En lo que respecta a la inmutabilidad, el valor ha cambiado, ¿verdad?

OnPush inmutabilidad de OnPush se refiere a propiedades de entrada, no propiedades de instancia normales. Si loadingMessage fuera una propiedad de entrada y el valor cambiara, la detección de cambios se ejecutaría en el componente. (Ver la respuesta de @Vlado para Plunker).

¿Cómo debe implementarse el componente interno liviano (es decir, loadingMessage ) al usar ChangeDetectionStrategy.OnPush ? Si hay varias prácticas recomendadas, indíqueme la dirección correcta.

Esto es lo que sé hasta ahora:

  • Si cambiamos el estado interno como parte del manejo de un evento, o como parte de un disparo observable, la detección de cambios se ejecuta en el componente OnPush (es decir, la vista se actualizará). En su caso particular, me sorprendió que la vista no se actualizara. Aquí hay dos conjeturas sobre por qué no:
    • Agregar delay() hace que Angular lo vea más como un setTimeout() lugar de un cambio observable. setTimeout s no da como resultado la ejecución de detección de cambios en un componente OnPush . En su ejemplo, Change Detector ha completado su trabajo 2 segundos antes de que se loadingMessage el valor de loadingMessage .
    • Al igual que @Sasxa muestra en su respuesta, debe tener un enlace en la plantilla para el Observable . Es decir, tal vez es algo más que "un incendio observable" ... tal vez tiene que ser un observable atado que dispare. En ese caso, la creación de loadingMessage (o incluso una propiedad de state más genérica) como un Observable mismo le permitirá vincular su plantilla a su valor (o múltiples valores asíncronos), vea este ejemplo plnkr .
      Actualización 2016-04-28: parece que el enlace debe incluir | async | async , como se muestra en el plnkr, y en este plnkr .
  • Si cambiamos el estado interno y no es parte del manejo de eventos o de un disparo observable, podemos inyectar ChangeDetectorRef en nuestro componente y llamar al método markForCheck() para que la detección de cambios se ejecute en el componente OnPush y todos los componentes antecesores hasta la raíz componente. Si solo se cambia el estado de la vista (es decir, el estado que es local para el componente y tal vez sus descendientes), en su detectChanges() puede usarse detectChanges() , que no marcará todos los componentes ancestrales para la detección de cambios. Plunker

Con esta ChangeDetectionStrategy.OnPush le está diciendo a su componente que solo escuche los cambios en sus propiedades de entrada.

Agregué el componente de carga a su ejemplo solo para mostrarle cómo funciona: http://plnkr.co/edit/k5tkmcLlzkwz4t5ifqFD?p=preview