Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React to nested state change in Angular and NgRx

Please consider the example below

// Example state
let exampleState = {
  counter: 0;
  modules: {
    authentication: Object,
    geotools: Object
  };
};

class MyAppComponent {
  counter: Observable<number>;
  constructor(private store: Store<AppState>){
    this.counter = store.select('counter');
  }
}

Here in the MyAppComponent we react on changes that occur to the counter property of the state. But what if we want to react on nested properties of the state, for example modules.geotools? Seems like there should be a possibility to call a store.select('modules.geotools'), as putting everything on the first level of the global state seems not to be good for overall state structure.

Update

The answer by @cartant is surely correct, but the NgRx version that is used in the Angular 5 requires a little bit different way of state querying. The idea is that we can not just provide the key to the store.select() call, we need to provide a function that returns the specific state branch. Let us call it the stateGetter and write it to accept any number of arguments (i.e. depth of querying).

// The stateGetter implementation
const getUnderlyingProperty = (currentStateLevel, properties: Array<any>) => {
  if (properties.length === 0) {
    throw 'Unable to get the underlying property';
  } else if (properties.length === 1) {
    const key = properties.shift();
    return currentStateLevel[key];
  } else {
    const key = properties.shift();
    return getUnderlyingProperty(currentStateLevel[key], properties);
  }
} 

export const stateGetter = (...args) => {
  return (state: AppState) => {
    let argsCopy = args.slice();
    return getUnderlyingProperty(state['state'], argsCopy);
  };
};

// Using the stateGetter
...
store.select(storeGetter('root', 'bigbranch', 'mediumbranch', 'smallbranch', 'leaf')).subscribe(data => {});
...
like image 339
Aleksandr Shumilov Avatar asked Mar 07 '23 01:03

Aleksandr Shumilov


1 Answers

select takes nested keys as separate strings, so your select call should be:

store.select('modules', 'geotools')
like image 52
cartant Avatar answered Mar 09 '23 14:03

cartant