如何在 Angular 中结合 NGRX 信号存储和路由解析器

问题描述 投票:0回答:1

我想将信号存储“附加”到我的一个组件上。我打算在组件级别而不是根级别提供此功能,因为状态特定于该组件。

但是,我喜欢使用路由解析器来防止导航到损坏的页面 - 在这种情况下,如果检索数据出现问题,我不会加载我的组件。

如果不从根本上提供信号存储,是否有任何模式可以帮助我在解析器、组件和信号存储之间共享数据,以便我可以同时获得解析器和信号存储的好处?

angular ngrx
1个回答
0
投票

您可以使用路线

providers
数组。这样做时,服务将在路由级别实例化。

它看起来像这样:

bootstrapApplication(App, {
  providers: [
    provideRouter([
      {
        path: 'a',
        component: AComponent,
        providers: [Store],
        resolve: {
          data: (
            route: ActivatedRouteSnapshot,
            state: RouterStateSnapshot
          ) => ({
            storeInstanceNumber: inject(Store).instanceNumber,
          }),
        },
      },
      {
        path: 'b',
        component: BComponent,
        providers: [Store],
        resolve: {
          data: (
            route: ActivatedRouteSnapshot,
            state: RouterStateSnapshot
          ) => ({
            storeInstanceNumber: inject(Store).instanceNumber,
          }),
        },
      },
    ]),
  ],
});

向您展示一个组件,它看起来像这样:

@Component({
  selector: 'app-a',
  standalone: true,
  template: `
    <h1>Component A</h1>
    <div>Store instance number: {{ store.instanceNumber }}</div><br />
    <div>Route data: <pre>{{ routeData | async | json }}</pre></div>
  `,
  imports: [CommonModule],
})
export class AComponent {
  public readonly store = inject(Store);
  public readonly routeData = inject(ActivatedRoute).data;
}

这只是为了证明您可以在解析器和组件中注入存储。

这是 Stackblitz 上的 现场示例

请注意,这样做时,在路由级别提供的

Store
仅在每个路由上创建一次,而不是每个组件实例化一次。根据您的需求,这可能是一个功能,也可能是一个问题:离开一条路线并返回该路线,您仍然可以获得所有可用数据。

无论你想要什么,这两种情况都可以实现。这是一个示例,每次我们返回路线

a
时都会给出一个新实例,并为路线
b
保留相同的 Store 实例:

bootstrapApplication(App, {
  providers: [
    provideRouter([
      {
        path: 'a',
        component: AComponent,
        resolve: {
          store: (route: ActivatedRouteSnapshot, state: RouterStateSnapshot) =>
            // small hack to create a new Store instance every time we open that route
            Injector.create({
              providers: [Store],
              parent: inject(Injector),
            }).get(Store),
        },
      },
      {
        path: 'b',
        component: BComponent,
        // here we'll get the same Store instance if we leave and come back
        providers: [Store],
        resolve: {
          data: (
            route: ActivatedRouteSnapshot,
            state: RouterStateSnapshot
          ) => ({
            storeInstanceNumber: inject(Store).instanceNumber,
          }),
        },
      },
    ]),
  ],
});

对于组件 B,您无需更改任何内容,可以照常注入

Store

对于组件 A,我们需要稍微调整代码,因为我们现在在路由数据中接收 Store 实例:

// this component receives a new Store instance every time it's been created
@Component({
  selector: 'app-a',
  standalone: true,
  template: `
    <h1>Component A</h1>
    <div>Store instance number: {{ store.instanceNumber }}</div><br />
  `,
  imports: [CommonModule],
})
export class AComponent {
  public readonly store:Store = inject(ActivatedRoute).snapshot.data['store']
}

这是此解决方案的 另一个 Stackblitz 。如果您交替转到

a
,然后转到
b
几次,您会在视图中看到
a
上的计数器增加,但在
b
中保持相同的值。

© www.soinside.com 2019 - 2024. All rights reserved.