NgRX signal store custom named store feature

Discussão em 'Angular' iniciado por Emanuel Vintilă, Janeiro 27, 2025.

  1. I have a NgRX signal store like so:

    type ResultType = any;
    export const MyCollectionsStore = signalStore(
    withState<{
    loading: boolean;
    loadingError: string | null;
    result: ResultType | null;
    }>({
    loading: false,
    loadingError: null,
    result: null,
    }),
    withMethods((store, collectionsApiService = inject(CollectionsService)) => ({
    loadPage: rxMethod<{ page: number; itemsPerPage: number }>(
    pipe(
    tap(() => patchState(store, { loading: true, loadingError: null })),
    switchMap(({ page, itemsPerPage }) => {
    return collectionsApiService
    .getMyCollections(page, itemsPerPage)
    .pipe(
    tapResponse({
    next: (result) => patchState(store, { result }),
    error: (e) => patchState(store, { loadingError: `${e}` }),
    finalize: () => patchState(store, { loading: false }),
    }),
    );
    }),
    ),
    ),
    })),
    );


    I would like to extract the withState and withMethods calls in a separate signalStoreFeature, but I want it to accept a name, like the named entity collections of the withEntities feature.

    I figured out the state, but I'm still struggling on the methods part:

    export type StatefulMethodResultState<TResult extends object> = {
    loading: boolean;
    loadingError: string | null;
    result: TResult | null;
    };

    export type NamedStatefulMethodResultState<
    TResult extends object,
    TName extends string,
    > = {
    [K in TName as `${K}State`]: StatefulMethodResultState<TResult>;
    };

    export const withStatefulMethodResult = <
    TResult extends object,
    TName extends string,
    >(
    method: (...params: any) => any,
    name: TName,
    ) => {
    return signalStoreFeature(
    withState<NamedStatefulMethodResultState<TResult, TName>>({
    [`${name}State`]: {
    loading: false,
    loadingError: null,
    result: null,
    },
    } as NamedStatefulMethodResultState<TResult, TName>),
    withMethods((store) => ({
    [name]: () => method(store),
    })),
    );
    };


    I'm not sure what type I need to specify on the method parameter. Also I obviously would like to be able to inject stuff in the method when I declare it, so the consuming code would look something like this:

    withStatefulMethodResult(
    (
    store,
    collectionsApiService = inject(CollectionsService),
    ) =>
    pipe(
    tap(() => patchState(store, { loadPageState: { loading: true, loadingError: null } })),
    switchMap(({ page, itemsPerPage }) => {
    return collectionsApiService.getMyCollections(page, itemsPerPage).pipe(
    tapResponse({
    next: (result) => patchState(store, { loadPageState: { result } }),
    error: (e) => patchState(store, { loadPageState: { loadingError: `${e}` } }),
    finalize: () => patchState(store, { loadPageState: { loading: false } }),
    }),
    );
    }),
    ),
    'loadPage',
    );


    Ideally I would like an answer for NgRX, but if NgRX isn't the right tool for this job I'm open to other suggestions.

    Continue reading...

Compartilhe esta Página