NgRx (2)

El Patron Redux
Como mencionamos en la entrada anterior de la serie (NgRx (1)) el patron Redux lo conforman tres elementos: La Store, la Accion y el Reducer.
Vamos a implementar el patron para comprender su funcionamiento.
Estado
El Estado puede ser desde un tipo primitivo a uno o más objetos con cualesquiera propiedades sean necesarias.
export interface AppState {
contador: number;
}
Store
Podemos representar el Store como una clase genérica, cuyo tipo será el State de la aplicación y cuya misión sería la de almacenar el estado de la aplicación y proveer de métodos para el acceso al estado y a poder despachar acciones al reducer.
class Store {
state: T;
constructor(private reducer: Reducer, state: T) {
this.state = state;
}
getState() {
return this.state;
}
dispatch(accion: Action) {
this.state = this.reducer(this.state, accion);
}
}
Acción
La Acción viene dada por una interfaz, que llamaremos Action, cuya misión es cargar con el tipo con el que conoceremos a la acción y a la información que acarreará, tanto para los efectos como para el reducer.
export interface Action {
type: String;
payload?: any;
}
Crearemos la acciones implementando en un objeto dicha interfaz
const incrementadorAction: Action = {
type: 'INCREMENTAR'
}
Donde INCREMENTAR será el nombre con el que nos referiremos a ella.
Reducer
El reducer es el corazon del patron Redux. Lo implementaremos a través de un tipo de función.
export interface Reducer{
(state: T, action: Action): T;
}
La Solucion
Con las piezas sobre el tablero procedemos a ensamblar la solución.
En nuestro modulo principal importamos lo necesario y lo inicializamos
import { Store } from './myngrx/store';
import { AppState, contadorReducer } from './contador/contador.reducer';
import { incrementadorAction, multiplicarAction, resetAction } from './contador/contador.actions';
// Estado inicial
const initialState: AppState = {
contador: 10
};
const store = new Store(contadorReducer, initialState);
La variable store debe ser accesible en toda la aplicación para poder usar de forma correcta el patrón, o al menos accesible en los lugares donde necesitemos acceder al estado compartido.
Una vez definido el almacenamiento podemos empezar a despachar acciones
// Mostramos el estado inicial
console.log(store.getState());
// Despachamos acciones y mostramos a continuación el estado
store.dispatch(incrementadorAction);
console.log(store.getState());
store.dispatch(incrementadorAction);
console.log(store.getState());
store.dispatch(incrementadorAction);
console.log(store.getState());
store.dispatch(multiplicarAction);
console.log(store.getState());
store.dispatch(resetAction);
console.log(store.getState());
store.dispatch(incrementadorAction);
console.log(store.getState());
store.dispatch(incrementadorAction);
console.log(store.getState());
La clave está en comprender la relación intrínseca entre el Estado, que puede ser desde un tipo primitivo hasta un objeto más complejo y el Reducer que lo va a manejar a través de las acciones que recibirá. Una acción podrá desde no cambiar el estado (en NgRx es habitual) porque va a lanzar un efecto (que será el que despache las acciones que si modifican el estado) hasta realizar un cambio total en el estado.
Es Redux para mi?
No todos los proyectos se benefician del patrón Redux. Si trabajamos con múltiples componentes, que necesitan compartir información entre ellos, Redux nos ayudará enormemente al facilitarnos dicha compartición de manera segura y organizada, ofreciéndonos además un acceso orientado a eventos que nos da pie a organizar como vamos a manejar la concurrencia de la manera que más nos convenga.
Resumen
Hemos visto los tres componentes básicos del patrón Redux junto con un ejemplo práctico del mismo que podréis encontrar en mi repositorio Github.
En la próxima entrega veremos cómo usamos Redux en proyectos Javascript con el módulo Redux.
Gracias y hasta la próxima.