Angular中使用forroot和forchild
在本文中我们将深入探讨一些您可能已经见过的 Angular 模式和方法。我将讨论 Angular 管理依赖项辑器配置信息中经常会使用到的 forRoot 和 forChild 方法。
1. Angular 中的 forRoot 是什么?
当我们使用 Angular6 及以上版本创建服务时,Angular 会在@Injectable 中创建一个对象,并将其 ProvideIn 属性为设置为’root’
1 | import { Injectable } from "@Angular/core"; |
当然,我们完全可以将其设置为我们想要的任何模块。这意味着除非我们导入在“provideIn”中指定的模块,否则 UserService 将不可用。
forRoot 用于提供初始化模块及其组件所需的配置数据。此配置数据可以是从环境变量到 API 密钥的任何数据,用于以特定方式设置应用程序。
大多数 Angular 开发人员都使用过 RouterModule 中的 forRoot 静态方法。这是为应用程序配置整个路由模块的方法,Angular 会全局创建它。
该方法本身返回一个 ModuleWithProviders 对象,其包括两个属性:ngModule 一般就是当前模块的引用,providers 一般是一组 provider。
RouterModule.forRoot()
1 | static forRoot(routes: Routes, config?: ExtraOptions): ModuleWithProviders<RouterModule>; |
ModuleWithProviders
1 | export declare interface ModuleWithProviders<T> { |
2. 我们为什么需要 forRoot 和 forChild?
引入模块我们一般有 3 个方法:
直接导入
1
2
3
4
5
6
7import { XXXModule } from 'xxx.module'
({
imports: [
XXXModule
]
})如果 XXXModule 实现了 forRoot 方法,我们可以:
1
2
3
4
5
6
7import { XXXModule } from 'xxx.module'
({
imports: [
XXXModule.forRoot()
]
})如果 XXXModule 实现了 forChild 方法,我们可以:
1
2
3
4
5
6
7import { XXXModule } from 'xxx.module'
({
imports: [
XXXModule.forChild()
]
})
在 angular 中,对于一些公共的组件,指令,管道,当我们需要在某个模块中使用时,我们就需要在该模块中导入一次。
但公共的服务是只需要引入一次的。对于一个服务,我们一般只需要在 root 模块中引入一次,然后就可以在其他模块中使用了。
当我们导入 XXXModule 时,angular 会为我们注册该模块上面的所有服务,如果我们在多个模块中导入了 XXXModule 模块,XXXModule 模块上面的服务是不会重复注册的,因为 angular 会确保服务都是单例的,也就是说一个应用里只会有一个该服务的实例。这能确保我们用服务共享数据时,不同模块取到的数据是一致的。
但有一种情况 angular 处理不了,当我们懒加载某一个模块时,该模块上面的服务会重新注册,如果该服务已经被注册过了,就会造成应用中一个服务有多个实例的情况。
怎么能确保完全的单例呢?这个时候我们就需要借助 forRoot 和 forChild 了。
3. 一个有关 forRoot 和 forChild 方法的示例
我们来看一个有关 RouterModule forRoot 和 forChild 方法的示例。
1 | const routes: Routes = { |
正如您看到的, 在 Imports 数组中我们调用了 RouterModule 模块的 forRoot 方法, 并将事先定义好的参数 routes 传递给它, 该方法是静态的, 并需要接收一些必要参数.
1 | static forRoot(routes: Routes, config?: ExtraOptions): ModuleWithProviders<RouterModule>; |
当 Angular 创建应用程序的同时它会创建创建路由系统,并且在整个应用程序的生命周期, 路由系统都是有效的.
通常,forRoot 方法在应用程序中仅并调用一次,并且始终在根模块中存在。
1 |
|
观察 ModuleWithProviders,我们可以看到 providers 属性是可选的,他们的区别也是在 providers 上。我们可以将需要确保完全单例的服务移动到 forRoot 中去。在主模块中导入模块时通过 forRoot 方法导入,在子模块中导入模块时直接导入。这样就能确保服务只会注册一次了。
4. 创建自己的 forRoot()
您可以完全自由地创建自己的 forRoot 方法并将其放入您的模块中。毕竟,模块就是一个类。
这是一个关于如何提供核心模块实例并确保仅调用一次的示例!
1 | ({ |
正如我所说,这个方法可以被称为任何名称,但由于命名规范,我命名为 forRoot() 。它也可以接受参数。
例如,我可以将初始配置数据传递给模块及其组件.
让我们试着给模块传递初始配置。
1 |
|
5. Angular 中的 forChild 是什么
forChild 与 forRoot 非常相似。
在接下来的路由示例之中,需要指出的是此静态方法通常在功能模块中加载,这些功能模块通常加载到根模块中。它允许我们配置功能模块而不影响整个应用程序。
当加载模块本身时,惰性模块会创建服务和提供者的新实例。这是因为 Angular 使用另一个注入器来创建模块。一个单独的。
比如当我们调用 RoutingModule.forChild() 为子模块创建路由时, 不会再创建 RoutingService, 我们有多个路由模块时,在子模块中必须调用 forChild 方法。
让我们看一个例子。这是我们之前实现的惰性模块。
1 | const routes: Routes = { |
您可以在模块中为自己创建一个类似的方法,并且只能传递特定于功能的服务和提供者.
6. forRoot 和 forChild 之间的区别
让我们讨论并比较以下它们之间的差异。我将在这里重点关注 RouterModule,因为它是最常用的,并且对于理解它的工作原理也很有用。
让我们首先看看它们的相似之处:
- 声明路由器信息
- 管理路线
让我们再来看看它们的区别:
一个区别是 forRoot 通常用于整个应用程序,而 forChild 用于功能模块。
另一个关键区别是 forRoot 注册路由服务,而 forChild 则不注册!
也可以说它们具有不同的范围、使用频率以及对服务和 Provider 的访问。
7. 总结
总之,forRoot() 和 forChild() 是 Angular 中强大的方法,用于配置模块及其组件。虽然这两种方法的目的相似,但它们具有关键的差异,这使得它们在不同的环境中具有独特性和价值。
通过有效地使用 forRoot 和 forChild,您可以确保 Angular 应用程序已正确配置并准备好处理其所有要求。
8. Angular 系列文章
最新更新以及更多 Angular 相关文章请访问 Angular 合集 | 鹏叔的技术博客
9. 参考文档
Angular中使用forroot和forchild