【问题标题】:After ChangeDetectionStrategy.OnPush enabled UI doesn't update启用 ChangeDetectionStrategy.OnPush 后 UI 不更新
【发布时间】:2020-09-26 00:34:07
【问题描述】:

根据翻译变化:

     setTranslation(): void {
        this.translateService.stream(['Client.Dashboard', 'Client.Active-
Orders']).subscribe(res => {

          const sideMenu: SideMenuModel = {
            dashboard: res['Client.Dashboard'],
            activeOrders: res['Client.Active-Orders'],

          };

          this.setSideMenu(sideMenu); // here it calls
        });
      }

我希望这是由于这里的不变性问题。即this.sideMenu。你能在这里给我任何提示吗?

setSideMenu(sideMenu: SideMenuModel): void {

    this.sideMenu = [
      {
        title: sideMenu.dashboard,
        url: '/dashboard',

      },
      {
        title: sideMenu.activeOrders,
        url: '/active-orders',

      },
]

我已启用changeDetection: ChangeDetectionStrategy.OnPush,。之后,UI 无法正确更新。

注意:我在这里删除了不需要的模板代码。

 <ion-menu-toggle auto-hide="false" *ngFor="let s of sideMenu; let i = index">

    <ion-item (click)="selectedIndex = i" routerDirection="root" [routerLink]="[s.url]">

    </ion-item>

  </ion-menu-toggle>

【问题讨论】:

    标签: angular typescript ionic-framework ionic5


    【解决方案1】:

    使用 OnPush 策略,您需要告诉您的组件更新外部事件/@Input(),例如可观察订阅:

         constructor(private readonly cdRef: ChangeDetectorRef) {}
         setTranslation(): void {
            this.translateService.stream(['Client.Dashboard', 'Client.Active-
    Orders']).subscribe(res => {
    
              const sideMenu: SideMenuModel = {
                dashboard: res['Client.Dashboard'],
                activeOrders: res['Client.Active-Orders'],
    
              };
    
              this.setSideMenu(sideMenu); // here it calls
              this.cdRef.markForCheck(); // Tell Angular to run detectChanges on this component
            });
          }
    

    【讨论】:

    • 是的,现在可以了。您能否提供有关此用例的更多信息?哪一个更好?即我应该使用没有OnPush 的默认行为还是使用OnPush 的方法。这是一个侧面菜单组件。哪个应用程序的性能更好?
    • 这不是因为this.sideMenu 的可变性问题吗?
    • 一点也不,对于 OnPush,sideMenu 应该是一个不同的参考,就像你做的那样:this.sideMenu = ...。如果您像 this.sideMenu.push(...) 一样改变 sideMenu 的状态,它将不起作用。应该有很多博客讨论 OnPush 的工作原理。我不认为我可以更好地解释。 OnPush 将具有更好的性能,因为检测更改运行的频率会降低,权衡是您需要编写更多代码,您可能会忘记它:您应该始终对属性使用不变性,并使用 ChangeDetectorRef.markForCheck() 和 @ 987654328@
    • 正如我所提到的,这是数据突变的问题。所以我使用了BehaviorSubjectasync 管道。现在它工作正常,没有任何黑客攻击。如果我使用 Google map Javascript API 等第三方库,您的解决方案很好。但是我在 Angular Zone 下工作的用例。即不需要ChangeDetectorRef。也感谢您的反馈。
    • 调用markForCheck() 不是黑客行为。将 BehaviorSubject 与 async Pipe 一起使用会使您的代码更加复杂,async Pipe 只是在底层调用 markForCheck()。我什至认为这很糟糕,因为您现在有两个 sideMenu 值来源...
    【解决方案2】:

    正如我在问题中提到的,这是数据突变的问题。所以我使用了BehaviorSubjectasync 管道。现在它工作正常,没有任何黑客攻击。

    关于此的精彩文章:https://blog.angular-university.io/onpush-change-detection-how-it-works/

    html

    <ion-menu-toggle *ngFor="let s of sideMenuChanged$ |async; let i = index">
    
    
      </ion-menu-toggle>
    

    .ts

      private sideMenuSubject$: BehaviorSubject<any> = new BehaviorSubject<any>(null);
      sideMenuChanged$: Observable<any> = this.sideMenuSubject$.asObservable();
    
      constructor(private translateService: TranslateService, ) { }
    
    ngOnInit(): void {
      this.setTranslation();
    }
    
     setTranslation(): void {
        this.translateService.stream(['Client.Dashboard', 'Client.Active-Orders']).subscribe(res => {
    
          const sideMenu: SideMenuModel = {
            dashboard: res['Client.Dashboard'],
            activeOrders: res['Client.Active-Orders'],
           };
    
          this.setSideMenu(sideMenu);
        });
      }
    
    setSideMenu(sideMenu: SideMenuModel): void {
    
        this.sideMenu = [
          {
            title: sideMenu.dashboard,
            url: '/dashboard',
            src: '../assets/images/client/dashboard-side-menu.png'
          },
          {
            title: sideMenu.activeOrders,
            url: '/active-orders',
            src: '../assets/images/common/active-orders.png',
            isActiveOrder: true
          },
         ];
    
        this.sideMenuSubject$.next(this.sideMenu);
      }
    

    【讨论】:

      猜你喜欢
      • 2012-11-06
      • 2010-11-13
      • 2013-07-06
      • 2017-05-05
      • 1970-01-01
      • 2020-04-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多