简体   繁体   中英

Angular 2 - ngrx subscribe running on every state change

I have a basic redux implementation with ngrx/store.

// root reducer

export const root = {
  posts: fromPosts.reducer,
  purchases: fromPurchases.reducer
}

export function getAllPosts( state ) {
  return fromPosts.getAll(state.posts);
}

export function getAllPurchases( state ) {
  return fromPurchases.getAll(state.purchases);
}

In my component, I'm selecting the state pieces.

this.posts$ = store.select(getAllPosts).do(c => console.log('posts$ change'));
this.purchases$ = store.select(getAllPurchases).do(c => console.log('purchases$ change'));

But on every change to the state, both the handler is running. For example, when I am adding a post, the purchases$ handler also runs.

All point is to run only the part that changed, or I am wrong?

This answer is wrong, but, for some reason, it was accepted. The implementation of select uses distinctUntilChanged , so the problem likely resides in the implementations of the OP's getAll functions.

Whenever an action is dispatched to the store, it's passed to the composed reducers and a new state is composed. That new state is then emitted.

So both of your observables will see a value emitted to the do operators, even when the selected slice of state has not changed.

However, it's simple to change this behaviour by using the distinctUntilChanged operator:

import 'rxjs/add/operator/distinctUntilChanged';

this.posts$ = store.select(getAllPosts)
  .distinctUntilChanged()
  .do(c => console.log('posts$ change'));

distinctUntilChanged will ensure that the observable only emits when the value has actually changed, so if the slice of state you are selecting has not changed, nothing will be emitted.

Your selectors are not using createSelector.

When using createSelector & when state changes createSelector memoizes return value based on it's parameter values.

When function defined with createSelector gets called again with the same parameters memoized return value is given & rest of the selector code is not run.

/**
 * Every reducer module exports selector functions, however child reducers
 * have no knowledge of the overall state tree. To make them usable, we
 * need to make new selectors that wrap them.
 *
 * The createSelector function creates very efficient selectors that are memoized and
 * only recompute when arguments change. The created selectors can also be composed
 * together to select different pieces of state.
 */
export const getBookEntitiesState = createSelector(
  getBooksState,
  state => state.books
);

Example use (albeit this is an old thread and example is from a newer NGRX) https://github.com/ngrx/platform/blob/master/example-app/app/books/reducers/index.ts#L58

Since The implementation of select uses distinctUntilChanged , and

distinctUntilChanged uses === comparison by default, object references must match. https://www.learnrxjs.io/operators/filtering/distinctuntilchanged.html

probably the problem relies in the fact that no matter what action is dispatched to your reducer , you return a new reference of the state (even when the state value has not been changed).

check in your reducer switch statement,the default section, probably it deep copies the state when no values are changed - therefore returnning a new reference and the selector executes again.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM