如何在Angular 2中在组件之间共享数据?
如何在Angular 2中在组件之间共享数据?
在Angular 1.x.x中,你只需要请求相同的服务,就会得到相同的实例,从而可以在服务中共享数据。
现在在Angular 2中,我有一个组件引用了我的服务。我可以读取和修改服务中的数据,这是好的。但是当我尝试在另一个组件中注入相同的服务时,似乎会得到一个新的实例。
我做错了什么?是模式本身有问题(使用服务来共享数据),还是我需要将服务标记为单例(在应用程序的一个实例中)或其他什么?
我使用2.0.0-alpha.27/
版本。
我通过appInjector
(现在是providers
)在@Component
注解中注入一个服务,然后在构造函数中保存一个引用。它在组件内部可以正常工作,但在不同的组件之间却不共享相同的服务实例,这与我之前的想法不同。
更新:从Angular 2.0.0开始,我们现在有了@ngModule,你可以在该@ngModule的providers
属性下定义服务。这将确保每个组件、服务等在该模块中使用相同的服务实例。
https://angular.io/docs/ts/latest/guide/ngmodule.html#providers
更新:Angular和FE开发已经有了很多变化。如@noririco所提到的,你还可以使用像NgRx这样的状态管理系统:
问题的原因是在组件中添加了providers属性,导致每次注入服务时都会创建一个新的实例,而不是使用单例模式。解决方法是只在模块中添加服务的providers属性,而在组件中不添加。
在Angular 2中,如何在组件之间共享数据?
问题的原因是在组件中添加了providers属性,这导致每次注入服务时都会创建一个新的实例,而不是使用单例模式。解决方法是只在模块中添加服务的providers属性,而在组件中不添加。
具体来说,当我们在组件中添加providers属性时,如下所示:
({ selector: 'my-selector', providers: [MyService], template: `stuff` })
这会导致每次注入MyService时都会创建一个新的实例。为了解决这个问题,我们只需要在应用的模块中添加MyService的providers属性,而在组件中不添加,如下所示:
import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { MyComponent } from './my-component'; import { MyService } from './my-service'; @NgModule({ imports: [BrowserModule], declarations: [MyComponent], providers: [MyService], // 在模块中添加服务的providers属性 bootstrap: [MyComponent] }) export class AppModule { }
这样,我们就可以在组件之间共享同一个MyService实例,而不是每次都创建一个新的实例。
需要注意的是,这并不意味着MyService是一个真正的单例,而是同一个实例在组件之间传递。如果需要一个新的实例,仍然可以通过注入MyService来实现。
在Angular 2中如何在组件之间共享数据?
在Angular 2中,有多种方法可以在组件之间共享数据。其中一种方法是使用服务单例。另一种方法是使用数据/事件绑定。
以下是两种方法的示例代码:
class BazService{ n: number = 0; inc(){ this.n++; } } @Component({ selector: 'foo', template: `` }) class FooComponent{ constructor(foobaz: BazService){ this.foobaz = foobaz; } } @Component({ selector: 'bar', properties: ['prop'], template: `` }) class BarComponent{ constructor(barbaz: BazService){ this.barbaz = barbaz; } } @Component({ selector: 'app', viewInjector: [BazService], template: ``, directives: [FooComponent, BarComponent] }) class AppComponent{} bootstrap(AppComponent);
通过使用服务单例或数据/事件绑定,我们可以在Angular 2中实现组件之间的数据共享。
注意:在Angular 2的较新版本中,`appInjector`已被移除,应该使用`viewInjector`代替。
因为在Angular 2中,组件之间不能直接共享数据,需要使用输入和输出装饰器来实现。下面是一个使用输入和输出装饰器的基本示例:
首先,我们需要在子组件中定义输入和输出的属性。子组件中的输入属性用于接收父组件传递过来的数据,输出属性用于向父组件传递数据。在这个例子中,子组件的输入属性是items,输出属性是onItemSelected。代码如下:
@Component({ selector: 'sub-component', inputs: ['items'], outputs: ['onItemSelected'], template: `{{ item }}` }) class SubComponent { onItemSelected: EventEmitter; items: string[]; constructor() { this.onItemSelected = new EventEmitter(); } select(i) { this.onItemSelected.emit(this.items[i]); } }
在父组件中,我们需要将子组件作为指令引入,并在模板中使用子组件,并传递数据给子组件的输入属性,并监听子组件的输出属性。在这个例子中,父组件的模板中使用了子组件,通过属性绑定将父组件的items属性传递给子组件的items属性,并监听子组件的onItemSelected输出属性,当子组件中的按钮被点击时,触发itemSelected方法。代码如下:
@Component({ selector: 'app', directives: [SubComponent], template: `` }) class App { items: string[]; constructor() { this.items = ['item1', 'item2', 'item3']; } itemSelected(item: string): void { console.log('Selected item:', item); } }
最后,我们需要使用bootstrap函数来启动应用程序,并将父组件作为参数传递给它。代码如下:
bootstrap(App);
在这个例子中,当子组件中的按钮被点击时,会触发itemSelected方法,将选中的item传递给父组件,并在控制台上输出选中的item。
需要注意的是,在模板中使用了Angular内置的ngFor指令来循环渲染子组件中的每个item。在这个例子中,我们不需要手动导入ngFor指令,因为它已经在Angular 2的common模块中,会自动被引入。