Handling side effects

What is a side effect? A side effect is something that isn't part of the normal code flow but something that accesses outside resources, such as filesystems or resources on other networks. In the context of Redux, side effects are most often used for carrying out AJAX calls. Once that call comes back, we most likely need to update the state of the store because something has changed. How would we implement such a function? One is add a method effect() that would take a function. The said function would take dispatch method as a parameter so that the parameter function can carry out a dispatch, should it have a need for it, once the side effect has run its course. Let's imagine it is being used in the following way:

// pseudo code

const store = new Store();

store.effect( async(dispatch) => {
const products = await getProducts();
dispatch({ type: 'LOAD_PRODUCTS', payload: products });
})

The preceding code shows how we in our side effect would want to carry out an AJAX call and fetch our products. Once we are done with our fetch, we want to dispatch the fetched products so they become part of the store's state. Let's attempt to implement the preceding effect() function:

// NGRX-light/storeVIII.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) ];
case 'LOAD_PRODUCTS':
return action.payload.map(p =>
Object.assign({}, p));
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]);
}

effect(fn) {
fn(this.dispatch.bind(this));
}

}

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

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' } });

const getProducts = () => {
return new Promise(resolve => {
setTimeout(() => {
resolve([{ id: 1, name: "Vader" }]);
}, 3000);
});

}

store.effect(async(dispatch) => {
const products = await getProducts();
dispatch({ type: 'LOAD_PRODUCTS', payload: products });
});

The preceding code does the following:

  • Adds a new case LOAD_PRODUCTS to the productsReducer
  • Implements the effect() method on the Store class
  • Defines a getProducts() method to simulate AJAX calls
  • Demonstrates the use of the effect method by carrying out a call to getProducts and ends up dispatching the fetched products to the store

We have now fully implemented the store and effects libraries for NgRx—we should be proud of ourselves.

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

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