web-dev-qa-db-ja.com

ngOnInitが2回呼び出されるのはなぜですか?

新しいコンポーネントResultComponentを作成しようとしていますが、そのngOnInit()メソッドが2回呼び出されており、なぜこれが発生するのかわかりません。コードでは、ResultComponentは親コンポーネント@Inputからmcq-componentを継承します。

コードは次のとおりです。

親コンポーネント(MCQComponent)

import { Component, OnInit } from '@angular/core';

@Component({
    selector: 'mcq-component',
    template: `
        <div *ngIf = 'isQuestionView'>
            .....
        </div>
        <result-comp *ngIf = '!isQuestionView' [answers] = 'ansArray'><result-comp>
    `,
    styles: [
        `
            ....
        `
    ],
    providers: [AppService],
    directives: [SelectableDirective, ResultComponent]
})
export class MCQComponent implements OnInit{
      private ansArray:Array<any> = [];
    ....
    constructor(private appService: AppService){}
    ....
}

子コンポーネント(result-comp)

import { Component, OnInit, Input } from '@angular/core';

@Component({
    selector:'result-comp',
    template: `
        <h2>Result page:</h2>

    `
})
export class ResultComponent implements OnInit{
    @Input('answers') ans:Array<any>;

    ngOnInit(){
        console.log('Ans array: '+this.ans);
    }
}

実行すると、console.logが2回表示されます。1回目は正しい配列を表示し、2回目はundefinedを表示します。私はそれを理解することができませんでした:ngOnInit in ResultComponentが2回呼び出されるのはなぜですか?

42
Shree

なぜ二度呼ばれるのか

現在、コンポーネントのコンテンツ/ビューの子の変更の検出中にエラーが発生した場合、ngOnInitが2回呼び出されます(DynamicChangeDetectorで表示)。これにより、元のエラーを隠すフォローアップエラーが発生する可能性があります。

この情報は、これに基づいています github issue


したがって、あなたの間違いは、このコンポーネントに関連するコードの他の場所にOriginを持っているようです。

37
Dylan Meeus

これは、コンポーネントHTMLの欠陥のために私に起こっていました。 Hostコンポーネントのセレクタータグを閉じるのを忘れていました。 <search><search>の代わりに<search></search>がありました-構文エラーに注意してください。

@dylanの回答に関連して、コンポーネントのHTML構造とその親の構造を確認してください。

16
orsonady

私の場合の問題は、子コンポーネントをブートストラップする方法でした。 my@ NgModuleデコレータのメタデータオブジェクトでは、 'child componentを渡していました'bootstapプロパティと'parent component ' bootstapプロパティで子コンポーネントを渡すことはresetting子コンポーネントpropertiesおよびOnInit()が2回発生しました。

@NgModule({
imports: [ BrowserModule,FormsModule ], // to use two-way data binding ‘FormsModule’
declarations: [ parentComponent,Child1,Child2], //all components
//bootstrap: [parentComponent,Child1,Child2] // will lead to errors in binding Inputs in Child components
bootstrap: [parentComponent] //use parent components only
})
14
Amardeep Kohli

app.module.tsでplatformBrowserDynamic().bootstrapModule(AppModule);を使用した場合は、コメントして試してください。同じ問題がありました。これが役立つと思う

12

誰かがここにくる場合に備えて、これをここに置きます。ブラウザのデフォルトボタンタイプが「送信」の場合、NgOnInitを2回呼び出すこともできます。たとえば、以下がある場合、ChromeではNextComponentのNgOnInitが2回呼び出されます。

<button class="btn btn-primary" (click)="navigateToNextComponent()">

修正するには、タイプを設定します:

<button class="btn btn-primary" type="button" (click)="navigateToNextComponent()">
9
user3689408

これは、AppComponentをデフォルトルートとして設定したために発生する可能性があります

RouterModule.forRoot([
    { path: '', component: AppComponent }  // remove it
])

注:AppComponentはデフォルトでangularで呼び出されるため、呼び出す必要はありません

7
WasiF

ngOnInit()は、すべてのディレクティブがインスタンス化された後に一度だけフックします。サブスクリプションinsidengOnInit()があり、サブスクリプションが解除されていない場合、サブスクライブされたデータが変更されると、再度実行されます。

次のStackblitzの例では、ngOnInit()内にサブスクリプションがあり、結果をコンソールします。一度読み込まれ、データが変更され、再び読み込まれるため、2回コンソールになります。

Stackblitz

3
Maihan Nijat

これは、テンプレートエラーがある場合に常に発生します。

私の場合、間違ったテンプレート参照を使用し、それを修正して問題を修正しました。

3
Bharat Raj

これは、<router-outlet>の中に*ngForsという名前を付けていないために起こりました。ループの各反復でロードされました。

その場合の解決策は、各アウトレットに一意の名前を付けるか、DOMに一度に1つだけ(たとえば[*ngIf)が1つだけ存在するようにすることです。

1
Kevin Beal

私の場合、これはコンポーネントがOnChangesOnInitの両方を実装しているときに起こります。これらのクラスのいずれかを削除してください。 ngAfterViewInitメソッドを使用することもできます。これは、ビューが初期化された後にトリガーされるため、1回呼び出されることが保証されます。

1
Cem Mutlu

私にとって、これはRouteで同じコンポーネントを2回登録したために起こりました。

{
        path: 'meal-services',
        children: [
          {
            path: '',
            component: InitTwiceComponent,
            canActivate: [AppVendorOpsGuard],
            data: { roleWhitelist: [UserRoles.Manage] }
          },
          {
            path: ':itemID',
            component: InitTwiceComponent,
            canActivate: [AppVendorOpsGuard],
            data: { roleWhitelist: [UserRoles.Manage] }
          }]
      },
}
0
MCMatan

私自身も同様の問題を抱えていました。コンポーネントを要求し、ルーターアウトレットを介して同じコンポーネントを参照していました。

<layout>
  <router-outlet></router-outlet>
</layout>

そして、アウトレットルートもレイアウトを指していました。

0
CodeMylife

私の場合、ngOnInit内にあったすべてのサブスクリプションのサブスクリプションを解除しませんでした。 ngOnDestroy内のすべてのサブスクリプションからnsubscribedを取得しただけで、問題は解決しました。

0
Sudharsan Prabu