You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 09:00:55