【问题标题】:Angular ngOnInit not working for the child componentAngular ngOnInit 不适用于子组件
【发布时间】:2020-04-19 23:21:01
【问题描述】:

请查看Stackblitz Editor 链接。我已经设置了一个角度应用程序。

Angular 应用的简要工作概述

  • 两个组件,即应用组件和子组件
  • 最初,子组件不显示。当我们点击按钮时,父应用组件中有一个按钮,我们启用一个变量'this.showChildComponent = true'。
  • 由变量 this.showChildComponent 控制的子组件。
  • 我使用 'firstParam' 和 'secondParam' 作为变量并将这些变量值发送到子组件。

现在,请看问题

当我们单击上面解释的按钮时,将调用已安装的子组件和 ngOnInit 方法,您也可以在控制台屏幕上查看消息“ngOnInit called: child component”但是如果我再次点击按钮,然后子组件不再重新渲染,因此子组件的ngOnInit方法没有被调用。

// This method is defined in the app-component (parent) and it is called when user clicks on 
// button
showChild() {
    if (this.showChildComponent)
    {
      this.showChildComponent = false;
    }
    this.showChildComponent = true;
    // child component ngOnInit call when
    // I use the timer
    // setTimeout(()=> {this.showChildComponent = true;}, 10);
    this.firstParam = 'first param from parent';
    this.secondParam = 'second param from parent';
  }

// Parent component - app-component
<button (click)="showChild()">Click here to display the child component</button>

<div *ngIf="showChildComponent">
  <app-child-component
    [first_param]="firstParam"
    [second_param]="secondParam"
  ></app-child-component>
</div>

正如您在代码中看到的,如果我使用 setTimeout,那么每当我单击父组件按钮时,都会调用子组件 ngOnInit 方法。 但我不想在这里使用计时器,解决此问题的替代解决方案是什么?每当用户点击按钮时,都会调用子组件的 ngOnInit 方法。

【问题讨论】:

  • 当用户再次点击按钮时,你想在子组件中实现什么?
  • @YogendraR 每当用户点击按钮时,应该调用子组件的 ngOnInit 方法。
  • 这就是我要问的,你想在每次点击按钮时在 ngOnInit 中做什么。这里的用例是什么?如我所见,您也不想破坏孩子。
  • @Shubham 在更改检测有机会读取到更改之前,您已将其设置为 false 和 true。这意味着子组件不会被删除然后重新添加。这就是为什么它使用超时来工作的原因,因为超时将在更改检测后执行。如果您真的希望行为在 ngOnInit 中运行,那么您需要使用 settimeout 来等待组件被销毁。
  • @jgerstle 感谢您的投入和时间。但是是否有替代方法来销毁子组件?

标签: javascript angular


【解决方案1】:

从评论中复制以提供一些答案参考:

在更改检测生效之前,您已将其设置为 false 和 true 有机会读到有变化。这意味着孩子 组件不会被删除然后重新添加。这就是它起作用的原因 通过使用超时,因为超时将在 变化检测。如果您真的希望行为在 ngOnInit 那么你需要使用 settimeout 来等待 要销毁的组件。

由于您似乎不想使用 setTimeout,即使我建议这样做,您也可以使用here 提供的方法之一强制更改检测。这是您原始问题的stackblitz fork,使用第三种方法。

【讨论】:

  • 感谢您的回答,但为什么我们不能使用 changeDetection Ref 手动检测更改。 changeDetection ref 或 application ref 之间有什么区别吗?
  • 老实说这可能会更好,我只是选择了第一个结果来证明它可以解决您的问题。稍后我可以尝试使用changeDetectionRef 发布堆栈闪电战
  • 好的,我稍后会更新答案,因为我认为使用 changeDetectionRef 更正确,因为您不会导致整个应用程序运行更改检测周期
  • 我将 stackblitz 示例更改为使用第三个建议
【解决方案2】:

试试这个来切换你的组件:

  showChild() {
    this.showChildComponent = !this.showChildComponent;
    this.firstParam = 'first param from parent';
    this.secondParam = 'second param from parent';
  }

【讨论】:

    【解决方案3】:

    您需要在if 语句中添加一些附加条件。现在,逻辑总是将this.showChildComponent 分配给true(即使您已经将它分配给false)。将您的 showChild 方法更改为:

    showChild() {
        if (this.showChildComponent)
        {
          this.showChildComponent = false;
        } else {
          this.showChildComponent = true;
        }
        // child component ngOnInit call when
        // I use the timer
        // setTimeout(()=> {this.showChildComponent = true;}, 10);
        this.firstParam = 'first param from parent';
        this.secondParam = 'second param from parent';
      }
    

    您之前总是将showChildComponent 属性设置为true,并且从未破坏孩子。因此,它永远不会重新渲染。

    【讨论】:

    • 我不想实现切换功能。请重新阅读说明。
    • ngOnInit 在组件创建时只被调用一次。即使在您的setTimeout 场景中,您仍在破坏原始组件,这是您能够“重新调用”ngOnInit 的唯一原因。再次调用ngOnInit 的唯一方法是销毁并重新安装您的原始组件,您可以通过超时完成,或者您可以通过销毁原始组件来完成(例如在切换中)。
    • 有没有其他方法可以在不使用超时和切换的情况下销毁组件?
    • 如果你想根据父级的变化重新渲染子级的一些信息,你可以使用ngOnChanges (OnChanges) 生命周期,但是你必须传递一些新的父母给孩子的信息。不过,这并不会真正破坏组件——它只会重新渲染任何已更改的内容。但是,真正销毁组件的唯一方法是将其从 DOM 中取出,我认为如果不将该变量设置为 false,您将无法做到这一点。
    • 您不能在同一个组件实例上调用ngOnInit 两次。您只能调用一次。只有在您销毁原始组件后才会“再次”调用它。如果您将ngIf 更改为false,那么您将销毁该组件。销毁的唯一方法是将该组件从 DOM 中取出。而且,在您的场景中,您使用的 boolean 是您将组件从 DOM 中取出的方式。您需要通过一些切换来更改该变量。从技术上讲,您的setTimeout 是一个切换开关。由于setTimeout 的“异步”性质,它只是感觉不同。
    【解决方案4】:

    为此,您可以使用ChangeDetectorRef 手动触发子组件

    创建一个ChangeDetectorRef 的实例并在应用组件中像下面这样使用。

    this.changeDetectorRef.detectChanges();

    或者实现此目的的替代方法是使用ngOnChanges,每次将参数作为输入传递给子组件时,它都会改变。这是一个使用 ngOnChanges 生命周期钩子的stackblitz fork。

    【讨论】:

      猜你喜欢
      • 2018-01-08
      • 2020-01-16
      • 2021-09-08
      • 1970-01-01
      • 2020-07-20
      • 2018-02-22
      • 2019-01-31
      • 2018-08-01
      • 2017-02-26
      相关资源
      最近更新 更多