如何在Ngrx Signal Store的onInit中传入参数加载数据?
Ngrx Signal Store:基于组件Input初始化加载数据的正确姿势
不需要放弃Store的hooks,但更推荐用响应式的方式处理组件Input的变化,比直接用组件ngOnInit更符合Signal Store和Angular Signals的设计。下面给你两种可行的方案,按需选择:
方案一:组件监听Input信号触发加载(推荐,支持动态id)
你的id是组件的input.required<number>(),本质是一个Signal。如果id可能动态变化(比如路由参数更新),用effect监听信号变化,调用Store的加载方法是最合理的——既保留了Store的数据逻辑封装,又能响应id的变化。
修改组件代码:
@Component({ // ... 原有配置 standalone: true, providers: [PostsStore], changeDetection: ChangeDetectionStrategy.OnPush }) export class ImageProcessing360ContainerComponent { id = input.required<number>() store = inject(PostsStore) constructor() { // 监听id信号,每次变化自动触发加载 effect(() => { this.store.loadPosts(this.id()); }); } }
调整Store代码(移除无用的hooks):
import { EMPTY } from 'rxjs'; export const PostsStore = signalStore( withState<PostsStateInterface>({ post: {}, error: null, isLoading: false }), withMethods((store, postsService = inject(PostsService)) => ({ loadPosts: rxMethod<number>( pipe( // 加载前更新状态 tap(() => patchState(store, { isLoading: true, error: null })), switchMap((id) => { return postsService.getPost(id).pipe( tap((post) => { patchState(store, { post, isLoading: false }) }), // 捕获错误并更新状态 catchError((error) => { patchState(store, { error, isLoading: false }); return EMPTY; }) ) }) ) ) })) )
这种方式的优势:
- 自动响应id的动态变化,无需手动处理更新
- 组件负责接收外部输入,Store负责数据逻辑,职责清晰
- 完全符合Signals的响应式设计理念
方案二:给Store注入初始化id(适合固定id场景)
如果你的id在Store初始化后不会变化,可以通过依赖注入把id传递给Store,再在withHooks的onInit里调用加载方法。
步骤1:定义传递id的InjectionToken
import { InjectionToken } from '@angular/core'; export const POST_ID = new InjectionToken<number>('POST_ID');
步骤2:修改Store代码注入id
import { EMPTY } from 'rxjs'; export const PostsStore = signalStore( withState<PostsStateInterface>({ post: {}, error: null, isLoading: false }), withMethods((store, postsService = inject(PostsService)) => ({ loadPosts: rxMethod<number>( pipe( tap(() => patchState(store, { isLoading: true, error: null })), switchMap((id) => { return postsService.getPost(id).pipe( tap((post) => { patchState(store, { post, isLoading: false }) }), catchError((error) => { patchState(store, { error, isLoading: false }); return EMPTY; }) ) }) ) ) })), withHooks({ onInit(store) { const postId = inject(POST_ID); store.loadPosts(postId); }, }) )
步骤3:组件提供id的依赖值
@Component({ // ... 原有配置 standalone: true, providers: [ PostsStore, { provide: POST_ID, useFactory: () => { // 注入组件实例获取id信号的值 const component = inject(ImageProcessing360ContainerComponent); return component.id(); } } ], changeDetection: ChangeDetectionStrategy.OnPush }) export class ImageProcessing360ContainerComponent { id = input.required<number>() store = inject(PostsStore) }
注意:这种方式仅适用于id固定的场景,如果id后续变化,Store不会自动重新加载数据(因为onInit只执行一次)。
要不要用组件的ngOnInit?
可以用,但不推荐——ngOnInit是Angular的生命周期钩子,只会执行一次,无法处理id动态变化的情况。而用effect是响应式的,会自动跟踪信号变化,更符合现代Angular的设计。
内容的提问来源于stack exchange,提问作者Freezy
相关产品推荐
相关产品推荐

