Implementing a reducer and integrating it with the store

An important concept of Redux is to guard who and what can affect your store. The who is reducers. By allowing only reducers to affect your store, we are more in control of what happens. A simple reducer is just a function that takes a state and action as parameters and is able to produce a new state based on the old state and existing state, like so:

// example reducer

function countReducer(state = 0, action) {
switch(action.type) {
case "INCREMENT":
return state + 1;
default:
return state;
}
}

let state = countReducer(0, { type: "INCREMENT" });
// 1
state = countReducer(state, { type: "INCREMENT" });
// 2

So, where does a reducer come into the picture in Redux? Well, the state of the store is made up of an object, like so:

{
counter: 1
products : []
}

The way a store goes about calculating the next state of a store is by creating a function that looks something like this:

// calculate state
function calcState(state, action) {
return {
counter: counterReducer(state.counter, action),
products: productsReducer(state.products, action)
}
}

With the preceding code, we are able to let different reducer functions handle different parts of our state. Let's add such a function to our store along with some reducers:

// NGRX-light/storeVI.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);
}
}

const store = new Store();
store.subscribe(data => console.log('store', data));

store.dispatch({ type: 'INCREMENT' });
store.dispatch({ type: 'INCREMENT' });
store.dispatch({ type: 'ADD_PRODUCT', payload: { id: 1, name: 'Yoda' } });

We have made quite a few changes to our store at this point:

  • We  have added two reducers
  • Now we inherit from a BehaviorSubject; this is so we can remember what the old state was so when we call calcState() we are able to produce a new state based on the old state + action
  • We added the method calcState() that takes the old state and an action
  • The dispatcher now takes an action instead of a state
  • The super() constructor in the constructor now takes an initial value 

We have set ourselves up quite well for our next step, namely on how to get a part of the state.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset