Angular组件间服务数据无法共享问题求助
问题描述
我创建了如下DataAccessService服务:
@Injectable({ providedIn: 'root', }) export class DataAccessService { constructor(private http: HttpClient) {} @Output() queryParamsChange: EventEmitter<any> = new EventEmitter(); _queryParams: any = null; set queryParams(value: any) { this._queryParams = value; this.queryParamsChange.emit(this._queryParams); } get queryParams(): any { return this._queryParams; }
该服务在app-root、app-home、app-study三个独立式组件中注入使用,Angular版本为17.3.6,且已在app.config.ts中注册该服务:
export const appProviders = [ provideRouter(routes), provideHttpClient(), provideAnimations(), importProvidersFrom( TranslateModule.forRoot({ defaultLanguage: 'fr', loader: { provide: TranslateLoader, useFactory: createTranslateLoader, deps: [HttpClient], }, }), KeycloakAngularModule, HttpClientModule ), { provide: APP_BASE_HREF, useValue: environment.baseHref }, { provide: LOCALE_ID, useValue: 'fr' }, { provide: HTTP_INTERCEPTORS, useClass: CacheInterceptor, multi: true, }, { provide: APP_INITIALIZER, useFactory: initializeKeycloak, multi: true, deps: [KeycloakService], }, { provide: AuthService, deps: [KeycloakService] }, KeycloakService, DataAccessService, ]; export const appConfig: ApplicationConfig = { providers: appProviders, };
各组件注入方式如下:
App组件
export class AppComponent implements OnInit { ... constructor( private dataService: DataAccessService, private router: Router, ) { ... }
Study组件
export class StudiesComponent implements OnInit, OnDestroy { routeNames: string[] = ['studies.toolbar.routeName']; queryParamsChange: Subscription; constructor(private dataService: DataAccessService) {} ngOnInit(): void { console.log('ON_INIT StudiesComponent'); console.log( 'queryParams : ' + JSON.stringify(this.dataService._queryParams) );
Home组件
export class HomeComponent implements OnInit { ... constructor( private dataService: DataAccessService, private router: Router ) {} onClick(route: string, value: any): void { console.log(value); this.dataService.queryParams = value; this.router.navigate([route]); }
问题现象
点击Home组件的按钮时,value已成功传入服务(日志验证有效),并通过router.navigate跳转至Study页面,但在StudiesComponent的ngOnInit中读取this.dataService.queryParams却返回Null。新增Test组件读取服务数据同样返回Null:
import { Component, OnInit } from '@angular/core'; import { DataAccessService } from '../services/data-access.service'; @Component({ selector: 'app-test', standalone: true, imports: [], templateUrl: './test.component.html', styleUrl: './test.component.scss', }) export class TestComponent implements OnInit { constructor(private dataService: DataAccessService) {} ngOnInit(): void { console.log('ON_INIT TestComponent'); const queryParams = this.dataService.queryParams; console.log('queryParams : ' + JSON.stringify(queryParams)); } }
问题原因及解决方案
核心原因
你同时通过两种方式提供了DataAccessService:
- 服务本身使用
@Injectable({ providedIn: 'root' }),Angular会自动将其注册为根级单例服务; - 又在
appConfig.providers中手动添加DataAccessService,导致Angular创建第二个独立实例。
Home组件注入的是第一个实例(root提供的),而Study/Test组件注入的是第二个实例(手动注册的),自然读取不到之前设置的值。
解决方案
只需保留一种服务提供方式即可,推荐移除appConfig.providers中的DataAccessService条目——providedIn: 'root'是Angular官方推荐的单例服务注册方式,更简洁且避免冲突。
修改后的appProviders:
export const appProviders = [ provideRouter(routes), provideHttpClient(), provideAnimations(), importProvidersFrom( TranslateModule.forRoot({ defaultLanguage: 'fr', loader: { provide: TranslateLoader, useFactory: createTranslateLoader, deps: [HttpClient], }, }), KeycloakAngularModule, HttpClientModule ), { provide: APP_BASE_HREF, useValue: environment.baseHref }, { provide: LOCALE_ID, useValue: 'fr' }, { provide: HTTP_INTERCEPTORS, useClass: CacheInterceptor, multi: true, }, { provide: APP_INITIALIZER, useFactory: initializeKeycloak, multi: true, deps: [KeycloakService], }, { provide: AuthService, deps: [KeycloakService] }, KeycloakService, // 移除该行:DataAccessService, ];
额外优化建议
- 服务中的
_queryParams不应让组件直接访问(比如Study组件中直接调用this.dataService._queryParams),始终通过get queryParams()获取,保证封装性; @Output()装饰器是为组件输出属性设计的,服务中直接使用EventEmitter即可,无需添加该装饰器。
修改后的服务:
@Injectable({ providedIn: 'root', }) export class DataAccessService { constructor(private http: HttpClient) {} // 移除@Output() queryParamsChange: EventEmitter<any> = new EventEmitter(); private _queryParams: any = null; // 改为private,禁止外部直接访问 set queryParams(value: any) { this._queryParams = value; this.queryParamsChange.emit(this._queryParams); } get queryParams(): any { return this._queryParams; }
完成上述修改后,所有组件都会注入同一个服务实例,数据即可正常共享。
内容的提问来源于stack exchange,提问作者STEPHANE
相关产品推荐
相关产品推荐

