我想将信号存储“附加”到我的一个组件上。我打算在组件级别而不是根级别提供此功能,因为状态特定于该组件。
但是,我喜欢使用路由解析器来防止导航到损坏的页面 - 在这种情况下,如果检索数据出现问题,我不会加载我的组件。
如果不从根本上提供信号存储,是否有任何模式可以帮助我在解析器、组件和信号存储之间共享数据,以便我可以同时获得解析器和信号存储的好处?
您可以使用路线
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
中保持相同的值。