angular - 是否可以将不同的服务实例传递给类似于 React Context 的子组件
问题描述
例如有这个服务
class Service {
constructor(public name:string){}
}
我想将它的不同实例传递给子组件
@Component({
selector: 'child-component',
template: `
<div>{{service.name}}</div>
`,
})
export class ChildComponent {
constructor(public service: Service){}
}
@Component({
selector: 'parent-component',
template: `
<child-component></child-component>
<child-component></child-component>
`,
})
export class ParentComponent {
constructor(public service: Service){}
}
在 React 中,它可以通过使用上下文来完成。像这样的东西
const ServiceContext = React.createContext<Service>({} as any);
function ChildComponent(){
const service = useContext(ServiceContext)
return <div>{service.name}</div>
}
export function ContextTest(){
const service1 = new Service("foo")
const service2 = new Service("bar")
return <div>
<ServiceContext.Provider value={service1}>
<ChildComponent/>
</ServiceContext.Provider>
<ServiceContext.Provider value={service2}>
<ChildComponent/>
</ServiceContext.Provider>
</div>
}
是否可以在 Angular 中做类似的事情?
解决方案
是的,这是可以做到的。诀窍是在providers
将使用它的组件数组中声明服务,而不是在Module
.
当您在该级别“提供”服务时Module
,单个实例可用于 DI 中的每个组件Module
。
但是,如果您在组件级别“提供”它,那么该组件每次都会获得一个全新的服务实例。
请查看此处的文档以获取更多信息。
@Component
使用您的组件装饰器之一的基本示例:
@Component({
selector: 'child-component',
template: `<div>{{service.name}}</div>`,
providers: [Service]
})
对每个需要它自己的实例的组件执行此操作,并再次确保您没有将服务放入Module's
providers
数组中。
编辑:
如果您希望父组件知道服务(及其值),那么它可以手动创建它们并通过@Input()
绑定传递它们。
举一个简单的例子,您的组件将具有如下属性:
@Input() service: Service;
然后在你父母的 HTML 中:
<child-component [service]="new Service('foo')"></child-component>
<child-component [service]="new Service('bar')"></child-component>
或者,在父级上创建字段,例如:
fooService = new Service('foo');
barService = new Service('bar');
然后在 HTML 中:
<child-component [service]="fooService"></child-component>
<child-component [service]="barService"></child-component>
编辑2:
虽然我不相信这可以使用 Angular 的 DI 开箱即用来实现,但我认为可能有一种方法可以实现所需的结果(并且仍然使用构造函数 DI)。
首先,创建一个“配置”类型,例如:
export interface ServiceConfig {
name: string;
}
现在,像这样修改您的服务:
export class Service {
private config: ServiceConfig;
constructor() {
}
registerConfig(config: ServiceConfig) {
this.config = config;
}
get name(): string {
return this.config.name;
}
}
然后在您的组件中:
@Component({
selector: 'child-component',
template: `<div>{{service.name}}</div>`,
providers: [Service]
})
export class ChildComponent implements OnInit {
@Input() serviceConfig: ServiceConfig;
constructor(private service: Service) {
}
ngOnInit(): void {
this.service.registerConfig(this.serviceConfig);
}
}
最后一件事是将独特的配置连接到父模板中的每个子组件:
<child-component [serviceConfig]="{ name: 'fooService' }"></child-component>
<child-component [serviceConfig]="{ name: 'barService' }"></child-component>
这并不完全是一个优雅的解决方案,但它满足了您(我认为非常奇怪)的要求。
推荐阅读
- c++ - How to limit char array length in constructor
- flutter - InheritedWidget 范围
- java - 没有来自 Web 应用程序 java servlet 的回复
- ruby - 方括号破坏 OAuth 签名生成 - 如何对其进行编码?
- python - Numpy 获取每列的 dtype
- count - 查找计数数据的分布
- yargs - 使用 Yargs 传递带空格的字符串
- html - VBA 无法使用 .getElementsByTag() 或 .getElementByID() 从 HTML 获取数据
- msbuild - How to use nuget.targets file to save two DLLs with same name but different target architecture into output respective folders in output directory
- android - DJI Mobile 示例 Sdk Android - Sdk 注册失败 [dji-sdk]