12
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

ExpressionChangedAfterItHasBeenCheckedErrorについて

Last updated at Posted at 2019-05-12

ExpressionChangedAfterItHasBeenCheckedErrorとは

子コンポーネントに値を渡した後に親コンポーネントの値が変わってたときに出てくるエラーみたいです。

エラーになる原因

Angular2の変更検知(change detection)

Angular2の変更検知オペレーションを理解しないとエラーになる原因がすっかり理解できないため、その処理を簡単にまとめてみます。

変更検知処理

チェックプロセス1

  • 子コンポーネント・ディレクティブにバウンディングしているプロパティを更新する
  • 子コンポーネントのngOnInit, onChanges, ngDoCheckをinvokeする
  • 現在のDOMを更新する
  • 子コンポーネントの変更検知処理(チェックプロセス1再帰)を実行する
  • 子コンポーネントのngAfterViewInitをinvokeする

引用元:Everything you need to know about the ExpressionChangedAfterItHasBeenCheckedError error

各ステップの各プロパティはコンポーネントのoldValuesプロパティに保存しています。上記の処理が終わったら、下記の処理(digest cycle)を行い、oldValuesに保存された値と現在コンポーネントの値の比較が行われます:

チェックプロセス2

  • oldValuesに保存された子コンポーネント用プロパティと現在コンポーネントもつ値が一致かどうかをチェック
  • oldValuesに保存された現在のDOMを更新プロパティと現在コンポーネント持つ値が一致かどうかをチェック
  • 子コンポーネントにチェックプロセス2を実行する

で、下記の例でエラーになる原因を説明させていただきます。
例えば、コンポーネントAと子コンポーネントBがあります。
コンポーネントAが子コンポーネントBに"text"プロパティを渡したい場合は:

  1. コンポーネントAのチェックプロセス1を実行する(textプロパティをoldValuesに記録する)
  2. コンポーネントBのチェックプロセス1を実行する(ここでおやコンポーネントAのtextプロパティが変った、理由は後ほど)
  3. コンポーネントAのチェックプロセス2を実行する
  4. oldValuesに記録されたtextプロパティと現在コンポーネントA持つtextプロパティが不一致のため、処理が中止され、ExpressionChangedAfterItHasBeenCheckedErrorがスローされます。

プロパティが変った原因

色々なケースがありますが、下記のようにコンポーネントBのngOnInit()で、おやコンポーネントAのtextプロパティを強制的に変更する例があります。:

export class BComponent {
    @Input() text;

    constructor(private parent: AppComponent) {}

    ngOnInit() {
        this.parent.text = 'updated text';
    }
}

引用元:Everything you need to know about the ExpressionChangedAfterItHasBeenCheckedError error

解決策

export class BComponent {
    @Input() text;

    constructor(private parent: AppComponent) {}

    ngOnInit() {
        // setTimeoutで、コンポーネントAのチェックプロセス2を先に実行させてから、おやコンポーネントAのプロパティ値を変更してもエラーにならない(チェック処理後値を変更するからだ)
        setTimeout(this.parent.text = 'updated text', 1000);
    }
}

まとめ

  • Angular2の変更検知処理がこのエラーになる原因です。
  • 子コンポーネントのライフサイクル・フックでおやコンポーネントのプロパティを変更するのは危ないです。
12
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?