The reason for wanting only part of the state is that we will use NgRx in a context where there will be many components that only care about rendering a little part of the application's full state. For example, we may have a product list component, a product detail component, and so on. For that reason, we need to implement support for getting a slice of state. Thanks to the fact that our store inherits from a BehaviorSubject, implementing a slice of state is child's play:
// NGRX-light/storeVII.js
const Rx = require('rxjs');
function counterReducer(state = 0, action) {
switch(action.type) {
case "INCREMENT":
return state + 1;
default:
return state;
}
}
function productsReducer(state = [], action) {
switch(action.type) {
case 'ADD_PRODUCT':
return [ ...state, Object.assign({}, action.payload) ]
default:
return state;
}
}
class Store extends Rx.BehaviorSubject {
constructor() {
super({ counter: 0, products: [] });
this.dispatcher = new Rx.Subject();
this.state = {};
this.dispatcher
.scan((acc, curr) => ({ ...acc, ...curr }))
.subscribe(data => this.next(data));
}
calcState(state, action) {
return {
counter: counterReducer(state.counter, action),
products: productsReducer(state.products, action)
}
}
dispatch(action) {
const newState = this.calcState(this.value, action);
this.dispatcher.next(newState);
}
select(slice) {
return this.map(state => state[slice]);
}
}
const store = new Store();
store
.select('products')
.subscribe(data => console.log('store using select', data));
// store using select, []
// store using select, [{ id: 1, name: 'Yoda' }]
store.subscribe(data => console.log('store', data));
store.dispatch({ type: 'INCREMENT' });
store.dispatch({ type: 'INCREMENT' });
// store 0
// store 1
store.dispatch({ type: 'ADD_PRODUCT', payload: { id: 1, name: 'Yoda' } });
Should we want a more advanced select method, we can let it take a function instead, like so:
// excerpt from the Store class
select(fn) {
return this.map(fn);
}
// usage - if there were such a state as 'state.products.list'
store
.select(state => state.products.list);