@Self和@Host Angular 2+依赖注入装饰器之间的区别 [英] Difference between @Self and @Host Angular 2+ Dependency Injection Decorators
问题描述
Angular API文档给出了一些想法.但是我不清楚.
为Self
提供的示例使用ReflectiveInjector
来举例说明用法.
但是,如果有的话,很少会在实际的应用程序代码中使用ReflectiveInjector
(在测试中可能会更多). @Host
在此类测试方案之外?
tl; dr
使用@Self
时,Angular只会为该指令/组件所在的元素寻找绑定在组件注入器上的值.
使用@Host
时,Angular会查找绑定到该指令/组件所在元素的组件注入器或父组件注入器上绑定的值. Angular将此父组件称为主机".
更多说明
尽管主要描述不是很有帮助,但看起来像 @Self 和 @Host 做得很体面,以阐明它们的用法以及它们之间的区别(在下面复制).
当试图理解这一点时,可能会有助于记住,当Angular依赖注入尝试为构造函数解析特定值时,它首先在注入器中查找当前组件,然后向上遍历父注入器.这是因为Angular使用分层注入器,并允许从祖先注入器继承.
因此,当@Host
文档说指定注入器应该从任何注入器检索依赖项,直到到达当前组件的宿主元素"时,这意味着一旦到达注入器,它将尽早停止此向上迭代.绑定到父组件.
@Self示例(源)
class Dependency {}
@Injectable()
class NeedsDependency {
constructor(@Self() public dependency: Dependency) {}
}
let inj = ReflectiveInjector.resolveAndCreate([Dependency, NeedsDependency]);
const nd = inj.get(NeedsDependency);
expect(nd.dependency instanceof Dependency).toBe(true);
inj = ReflectiveInjector.resolveAndCreate([Dependency]);
const child = inj.resolveAndCreateChild([NeedsDependency]);
expect(() => child.get(NeedsDependency)).toThrowError();
@Host示例(源)
class OtherService {}
class HostService {}
@Directive({selector: 'child-directive'})
class ChildDirective {
logs: string[] = [];
constructor(@Optional() @Host() os: OtherService, @Optional() @Host() hs: HostService) {
// os is null: true
this.logs.push(`os is null: ${os === null}`);
// hs is an instance of HostService: true
this.logs.push(`hs is an instance of HostService: ${hs instanceof HostService}`);
}
}
@Component({
selector: 'parent-cmp',
viewProviders: [HostService],
template: '<child-directive></child-directive>',
})
class ParentCmp {
}
@Component({
selector: 'app',
viewProviders: [OtherService],
template: '<parent-cmp></parent-cmp>',
})
class App {
}
使用@Self的示例很重要
比方说,您有一条指令,用于修改多种类型的组件的行为.也许此指令提供了某种配置支持.
此伪指令绑定到整个应用程序中的许多组件,并且此伪指令将其providers
列表中的某些服务绑定.想要使用此指令动态配置自身的组件将注入它提供的服务.
但是,我们要确保组件仅使用其自己的配置,并且不会意外注入用于某些父组件的配置服务.因此,我们使用@Self
装饰器告诉Angular的依赖项注入仅考虑此组件元素上提供的配置服务.
Kindly explain the difference between @Self
and @Host
.
The angular API documentation gives some idea. But it's not clear to me.
The example provided for Self
uses ReflectiveInjector
to exemplify usage.
However, one would rarely, if ever, use ReflectiveInjector
in actual app code (probably more in testing).. Can you give an example of where you would use @Self
instead of @Host
outside of such test scenarios??
tl;dr
It looks like when @Self
is used, Angular will only look for a value that is bound on the component injector for the element that this Directive/Component exists on.
It looks like when @Host
is used, Angular will look for a value that is bound on either the component injector for the element that this Directive/Component exists on, or on the injector of the parent component. Angular calls this parent component the "host".
More explanation
Although the main descriptions aren't very helpful, it looks like the examples in the documentation for @Self and @Host do a decent job of clarifying how they are used and what the difference is (copied below).
When trying to understand this, it might help to remember that when Angular dependency injection tries to resolve a particular value for a constructor, it starts by looking in the injector for the current component, then it iterates upward through parent injectors. This is because Angular uses hierarchical injectors and allows for inheritance from ancestor injectors.
So when the @Host
documentation says that it "specifies that an injector should retrieve a dependency from any injector until reaching the host element of the current component", that means that it stops this upward iteration early once it reaches the injector bound to the parent component.
@Self example (source)
class Dependency {}
@Injectable()
class NeedsDependency {
constructor(@Self() public dependency: Dependency) {}
}
let inj = ReflectiveInjector.resolveAndCreate([Dependency, NeedsDependency]);
const nd = inj.get(NeedsDependency);
expect(nd.dependency instanceof Dependency).toBe(true);
inj = ReflectiveInjector.resolveAndCreate([Dependency]);
const child = inj.resolveAndCreateChild([NeedsDependency]);
expect(() => child.get(NeedsDependency)).toThrowError();
@Host example (source)
class OtherService {}
class HostService {}
@Directive({selector: 'child-directive'})
class ChildDirective {
logs: string[] = [];
constructor(@Optional() @Host() os: OtherService, @Optional() @Host() hs: HostService) {
// os is null: true
this.logs.push(`os is null: ${os === null}`);
// hs is an instance of HostService: true
this.logs.push(`hs is an instance of HostService: ${hs instanceof HostService}`);
}
}
@Component({
selector: 'parent-cmp',
viewProviders: [HostService],
template: '<child-directive></child-directive>',
})
class ParentCmp {
}
@Component({
selector: 'app',
viewProviders: [OtherService],
template: '<parent-cmp></parent-cmp>',
})
class App {
}
Example of when using @Self is important
Let's say you have a directive that is used to modify the behavior of many types of components; maybe this directive provides some sort of configuration support.
This directive is bound to many components throughout your app and this directive binds some service in its providers
list. Components that want to use this directive to dynamically configure themselves will inject the service it provides.
However, we want to make sure that a component only uses its own configuration, and doesn't accidentally inject the configuration service that was meant for some parent component. So we use the @Self
decorator to tell Angular's dependency injection to only consider the configuration service provided on this component's element.
这篇关于@Self和@Host Angular 2+依赖注入装饰器之间的区别的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!