如何在Angular中结合外观模式使用NgRx SignalStore并初始化谷歌地图?
问题描述
在Angular项目中,我希望使用NgRx新推出的SignalStore获取网点位置并保存到状态中,目前遇到两个问题:
- 不知道如何等待位置请求的响应,在获取到位置后将其标记到谷歌地图上
- 想用
LOCATION_STORE替换原有的AtmsService
相关代码如下:
export const LOCATION_STORE = signalStore( { providedIn: "root" }, withState(() => inject(LOCATION_STORE_INITIAL_STATE)), withMethods((store, atmService: AtmsService = inject(AtmsService)) => ({ fetchLocations: rxMethod<void>(pipe( debounceTime(300), distinctUntilChanged(), tap(() => patchState(store, { loading: true })), mergeMap(() => atmService.getBranchesAndAtms().pipe( tapResponse({ next: (locations: Array<LocationModel>) => { const branches: Array<LocationModel> = locations.filter((res: LocationModel) => res.isBranch); const atms: Array<LocationModel> = locations.filter((res: LocationModel) => !res.isBranch); return patchState(store, { atms, branches }) }, error: (errorCode: string) => patchState(store, { error: errorCode }), finalize: () => patchState(store, { loading: false }) }) )) )), })) ) // 谷歌地图初始化代码 initiateMap(mapContainer: HTMLElement) { return forkJoin([ this.getGoogleMap(mapContainer), this._atmService.getBranchesAndAtms() ]).pipe( tap(([ googleMap, locations ]): void => { const markers: Array<google.maps.Marker> = this.addMarkers(locations); this.addMarkerClusterer(googleMap, markers); }) ) }
解决方案
1. 保留SignalStore核心逻辑,确保状态可观测
你的LOCATION_STORE定义已经正确实现了数据获取和状态更新逻辑,SignalStore会自动为状态中的atms、branches等属性生成对应的可观测信号(atms$、branches$),组件可以直接访问这些信号获取状态数据。
2. 替换AtmsService,实现等待位置响应的两种方式
方式一:订阅fetchLocations的返回值(适合单次初始化)
rxMethod返回的是Observable,可以直接和地图初始化请求并行处理,确保两者都完成后再渲染标记:
constructor(private locationStore: LOCATION_STORE) {} initiateMap(mapContainer: HTMLElement) { // 触发位置获取,并转换为合并后的全量位置列表 const locations$ = this.locationStore.fetchLocations().pipe( switchMap(() => combineLatest([ this.locationStore.atms$, this.locationStore.branches$ ])), map(([atms, branches]) => [...atms, ...branches]) ); // 并行等待地图加载和位置数据返回 return forkJoin([ this.getGoogleMap(mapContainer), locations$ ]).pipe( tap(([googleMap, locations]) => { const markers = this.addMarkers(locations); this.addMarkerClusterer(googleMap, markers); }) ); }
方式二:监听状态信号变化(适合自动响应状态更新)
如果希望状态更新时自动刷新地图标记,可以直接监听atms$和branches$的组合信号,无需手动订阅请求返回:
constructor(private locationStore: LOCATION_STORE) {} initiateMap(mapContainer: HTMLElement) { // 先触发数据获取 this.locationStore.fetchLocations(); // 组合并监听网点数据变化,过滤初始空状态 const combinedLocations$ = combineLatest([ this.locationStore.atms$, this.locationStore.branches$ ]).pipe( map(([atms, branches]) => [...atms, ...branches]), filter(locations => locations.length > 0) ); return forkJoin([ this.getGoogleMap(mapContainer), combinedLocations$ ]).pipe( tap(([googleMap, locations]) => { const markers = this.addMarkers(locations); this.addMarkerClusterer(googleMap, markers); }) ); }
3. 额外优化建议
- 避免重复请求:调用
fetchLocations前,可通过this.locationStore.atms$()判断是否已有数据,减少不必要的接口调用 - 错误处理:添加对
locationStore.error$信号的监听,处理位置请求失败的场景(比如显示错误提示) - 加载状态:利用
locationStore.loading$信号,在地图初始化过程中显示加载动画,提升用户体验
内容的提问来源于stack exchange,提问作者Giorgi Paradashvili
相关产品推荐
相关产品推荐

