I want a page to respond to a route param, retrieve the backend data associated with that param, and manage that data in a @ngrx/signals
signalStore
.
I'm experimenting with this approach, rather than loading the data using a resolver, because it will (in theory) allow me to load a placeholder page more quickly than waiting for the data and (hopefully) consolidate all my data management in my signal store.
However, I'm struggling to integrate the route param in the store directly in a signal-based way. Currently, I am setting up the route param signal in the component, and using an effect to update the store
@Component({ ... })
class MyComponent {
readonly store = inject(MySignalStore); // current implementation is irrelevant I think
readonly #updatePageId = effect(
() => {
// `selectRouteParam()` is a utility signal from '@ngrx/router-store'
const pageId = this.#store.selectSignal(selectRouteParam('pageId'))();
if (pageId) this.store.getDataForId(pageId);
},
{ allowSignalWrites: true }
);
}
This is ugly and I'd prefer to move this logic into my store directly, but I can't quite work out how. Is there something like effect()
in a signalStore()
where I ca n register an existing, external signal and apply computed()
properties from it?
I'm now setting this logic up within the onInit()
hook within the signal store...
import { Store, createFeatureSelector } from '@ngrx/store';
import { getRouterSelectors, createFeatureSelector } from '@ngrx/router-store';
import { rxMethod } from '@ngrx/signals/rxjs-interop';
import {
signalStore,
withHooks,
withMethods,
withState,
} from '@ngrx/signals';
import { pipe } from 'rxjs';
// Router State
export const selectRouter = createFeatureSelector<RouterReducerState>('router');
export const { selectRouteParam } = getRouterSelectors();
// Signal Store
export const MySignalStore = signalStore(
withState({ ... }),
withMethods({
getDataForId: rxMethod(
pipe( ... ) // implementation is irrelevant
)
}),
withHooks((store, global = inject(Store)) => ({
onInit(): void {
global
.select(selectRouteParam('pageId'))
.pipe(tap(store.getDataForId))
.subscribe();
},
}))
);
For simplicity, I've removed my custom unsubscribe operator, but there is also an onDestroy()
hook for that kind of logic.