• Angular踩坑ExpressionChangedAfterItHasBeenCheckedError异常


    和Angular打交道的过程中大概率会遇到ExpressionChangedAfterItHasBeenCheckedError,这个异常通常只在开发调试时会被抛出,生产环境里会被'吞掉', 虽然生产环境中看不到这个异常,但这并不意味着不需要处理这个问题; 出现这个异常可能导致ui上显示的数据和实际的不同步. 我在初学Angular时到现在已经多次遇到这个问题了, 所以在这里记录一下.

    问题复现

    通过Angular CLI创建一个Angular项目, 并准备两个组件AComponentBComponent, AComponentBComponent父组件; 然后创建一个SharedService, 这个SharedService包含两个属性titlename.

    SharedService

    import { Injectable } from '@angular/core';
    
    @Injectable({
      providedIn: 'root'
    })
    export class SharedService {
      title = '哈哈哈哈哈,我是title';
      name = '一个名字';
    
      constructor() { }
    }
    

    AComponentBComponent中都注入SharedService, 同时在子组件BComponentngOnInit方法中改变SharedService属性值

    AComponent:

    import { SharedService } from './../shared.service';
    import { Component, OnInit } from '@angular/core';
    
    @Component({
      selector: 'app-a',
      template: `<h2>{{ sharedServ.title }}</h2>
        <p>{{ sharedServ.name }}</p>
        <app-b></app-b>`,
      styleUrls: ['./a.component.css'],
    })
    export class AComponent implements OnInit {
      constructor(public sharedServ: SharedService) {}
    
      ngOnInit(): void {}
    }
    

    BComponent:

    import { SharedService } from './../shared.service';
    import { Component, OnInit } from '@angular/core';
    
    @Component({
      selector: 'app-b',
      template: `<p>{{ sharedServ.title }}</p>`,
      styleUrls: ['./b.component.css'],
    })
    export class BComponent implements OnInit {
      constructor(public sharedServ: SharedService) {
      }
    
      ngOnInit(): void {
        this.sharedServ.title = '标题被修改了';
      }
    }
    

    ng serve运行便可以在浏览器控制台看到ExpressionChangedAfterItHasBeenCheckedError异常

    这里我只是举了一个简单的例子, 实际情况可能比这要复杂很多, 但是大抵都是在组件中更新了父组件上模板中绑定的变量有关...

    解决方案

    解决方案有多种, 这里只记录其中一种我用起来比较顺手的;
    修改子组件ngOnInit方法中更新SharedService属性值的代码, 同步更新改为巧用Promise进行异步更新:

    ngOnInit(): void {
        Promise.resolve(null).then(() => {
            this.sharedServ.title = '标题被修改了';
        });
    }
    

    为什么同步更新改为异步更新后就不会出现ExpressionChangedAfterItHasBeenCheckedError的异常了呢? 简单来说就是异步更新的代码需要等待当前同步执行的代码执行完后, 才会执行. 这就使得Angular在本次变更检测中校验属性值时得以成功, 详细的变更检测的过程以及Angular为什么要防止属性值在一次变更检测被更改后面再有时间在记录.

    参考

    Everything you need to know about the ExpressionChangedAfterItHasBeenCheckedError error

    作者:Laggage

    出处:https://www.cnblogs.com/laggage/p/14811622.html

    说明:转载请注明来源

  • 相关阅读:
    2020/10/25助教一周小结(第八周)
    2020/10/18助教一周小结(第七周)
    2020/10/11助教一周小结(第六周)
    2020/10/05助教一周小结(第五周)
    2020/09/27助教一周小结(第四周)
    第三次作业总结
    第二次作业总结
    2020-11-08 助教一周小结(第十周)
    2020-11-01 助教一周小结(第九周)
    2020-10-25 助教一周小结(第八周)
  • 原文地址:https://www.cnblogs.com/laggage/p/14811622.html
Copyright © 2020-2023  润新知