实例化 Injectable 类时未调用 ngOnInit

Posted

技术标签:

【中文标题】实例化 Injectable 类时未调用 ngOnInit【英文标题】:ngOnInit not being called when Injectable class is Instantiated 【发布时间】:2016-05-08 17:35:27 【问题描述】:

为什么Injectable 类被解析后不调用ngOnInit()

代码

import Injectable, OnInit from 'angular2/core';
import  RestApiService, RestRequest  from './rest-api.service';

@Injectable()
export class MovieDbService implements OnInit 

    constructor(private _movieDbRest: RestApiService)
        window.console.log('FROM constructor()');
    

    ngOnInit() 
         window.console.log('FROM ngOnInit()');
    


控制台输出

FROM constructor()

【问题讨论】:

【参考方案1】:

Lifecycle hooks 与 OnInit() 一样,可用于指令和组件。它们不适用于其他类型,例如您的服务。来自文档:

组件的生命周期由 Angular 自己管理。 Angular 创建它,渲染它,创建和渲染它的子节点,当它的数据绑定属性发生变化时检查它,并在从 DOM 中删除它之前销毁它。

指令和组件实例在 Angular 创建、更新和销毁它们时具有生命周期。

【讨论】:

那么简单地将我的ngOnInit 逻辑移动到Injectable 类的构造函数中?我只记得读过,无论出于何种原因,您都应该将任何逻辑排除在构造函数之外。 @LeviFuller 是的,对于服务,您可以在构造函数中进行初始化,或者更好地创建 init 方法并从构造函数中调用它(以防您稍后需要重置服务)。 不完全是,OnInit 与绑定有关。当您想要等待解析输入值时使用它,因为它们在构造函数中不可用。构造函数可以被多次调用。例如,当您更改路线并加载不同的组件时,它们每次都会“构建”并销毁...... 这里还值得注意的是,服务可以多次实例化,具体取决于您将它们包含在providers 数组中的位置。如果你想要一个单例服务,把它放在你的主模块的providers,如果你想要每个组件的服务,直接把它们添加到组件中。 这并不完全不正确,因为@SBD580 在他的回答中指出,ngOnDestroy 被称为注入服务【参考方案2】:

我不知道所有的生命周期钩子,但至于销毁,ngOnDestroy 实际上在 Injectable 的提供者被销毁时被调用(例如由组件提供的 Injectable)。

来自docs :

当指令、管道或服务被销毁时调用的生命周期钩子。

以防万一有人对破坏感兴趣,请查看this问题:

【讨论】:

不调用 ngOnInit 真是太可惜了 :-( 我真的很想做一些透明的延迟初始化魔术。如果可以调用 ngOnDestroy 我不明白为什么 init 不能 【参考方案3】:

注意:此答案仅适用于 Angular 组件和指令,不适用于服务。

ngOnInit(和其他生命周期钩子)没有为我的组件触发时,我遇到了同样的问题,并且大多数搜索都把我带到了这里。

问题是我使用的是箭头函数语法 (=>),如下所示:

class MyComponent implements OnInit 
    // Bad: do not use arrow function
    public ngOnInit = () => 
        console.log("ngOnInit");
    

显然这在 Angular 6 中不起作用。使用非箭头函数语法解决了这个问题:

class MyComponent implements OnInit 
    public ngOnInit() 
        console.log("ngOnInit");
    

【讨论】:

可注入类是服务,而不是组件。 OP 询问服务。尽管从语言 POV 来看您的答案可能是正确的,但它并不能回答这个问题。你应该删除它。 @AndrewPhilips 虽然我的用例与 OP 的用例略有不同,但谷歌搜索“未调用 ngOnInit”会导致人们来到这里。我的这个答案的目标不是帮助 OP,而是帮助其他 70,000 多名可能对ngOnInit 有类似问题的观众。 很公平。我相信我看过 SO Q&A,作者提出问题然后回答他们自己的问题。作为一个新的 Angular 程序员,两周前你的回答会让我感到困惑。从 SO 和 NG 的角度来看,我认为您的答案值得提出自己的问题,因此没有被删除,而是“重新分类”。谁知道?也许它可能会接触到更广泛的受众。干杯。 有道理 - 我编辑了我的答案以明确表示这不适用于服务。【参考方案4】:

一旦我的 dataService 被初始化,我必须调用一个函数,相反,我在构造函数中调用它,这对我有用。

【讨论】:

【参考方案5】:
import Injectable, OnInit from 'angular2/core';
import  RestApiService, RestRequest  from './rest-api.service';
import Service from "path/to/service/";

@Injectable()
export class MovieDbService implements OnInit 

userId:number=null;

constructor(private _movieDbRest: RestApiService,
            private instanceMyService : Service )

   // do evreything like OnInit just on services

   this._movieDbRest.callAnyMethod();

   this.userId = this.instanceMyService.getUserId()



【讨论】:

这个问题是 "callAnyMethod" 只能是 synchoronous 方法,不能是 await'ed...【参考方案6】:

添加@Sasxa 的回答

Injectables 中,您通常可以使用class,将初始代码放入constructor 而不是使用ngOnInit(),它可以正常工作。

【讨论】:

以上是关于实例化 Injectable 类时未调用 ngOnInit的主要内容,如果未能解决你的问题,请参考以下文章

退出时未调用Angular AuthGuard CanActivate - Firebase Auth

以编程方式添加控件时未实例化占位符

实例化泛型类时如何避免指定冗余类型

依赖注入:在无参数构造函数中实例化具体类时你会失去啥

使用 UIGestureRecogniser 子类化时未调用 Touches Ended

Java继承,子类实例化时,调用父类的无参构造方法