Observing state changes in effects #4692
-
Hello all, I have a component store that keeps track of the current page as well as the active filters. There is also some form of pagination which will call the export interface ItemsState {
page: number; // current page
filters: Filter[]; // current active filters
items: []; // fetched items
}
@Injectable()
export class ItemsStore extends ComponentStore<ItemsState> {
// ...
fetchItems = this.effect(($) => $.pipe(
exhaustMap(() => this.select((state) => ({
page: state.page + 1,
filters: state.filters,
})).pipe(
switchMap((params) => {
return this.itemsService.getItems(params.page, params.filters).pipe(
tapResponse(
(items) => {
// update state, but this triggers the above selector again, causing to keep fetching the next page
this.patchState({
page: params.page,
// update items...
});
},
() => { /* some error handling */ },
),
);
}),
)),
));
} The issue here is that the I have also tried to use Is there a way to observe changes in the state and cancel the running effect or another NgRx way to achieve this? |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment
-
Yes there is a way. What you want is to have a selector that only emits a new value when your parameters have actually changed: @Injectable()
export class ItemsStore extends ComponentStore<ItemsState> {
// ...
// 👇 Declare selectors that can be memoized, and will only emit distinct values
page$ = this.select((state) => state.page);
filters$ = this.select((state) => state.filters);
// 👇 Then create a composite selector that will only emit a new value when one of the input selectors emits a new, distinct value
itemsRequestParams$ = this.select(
this.page$,
this.filters$,
(page, filters) => ({
page: state.page + 1,
filters: state.filters,
})
);
fetchItems = this.effect(($) => $.pipe(
exhaustMap(() => this.itemsRequestParams$).pipe(
switchMap((params) => {
return this.itemsService.getItems(params.page, params.filters).pipe(
tapResponse(
(items) => {
// update state, but this triggers the above selector again, causing to keep fetching the next page
this.patchState({
page: params.page,
// update items...
});
},
() => { /* some error handling */ },
),
);
}),
)),
));
} This concept applies to NgRx global store selectors that use Unrelated: I noticed you're using |
Beta Was this translation helpful? Give feedback.
Yes there is a way. What you want is to have a selector that only emits a new value when your parameters have actually changed: