Curso
ANGULAR 4 + REDUX
www.devcode.la
¿QUIÉN SOY?
www.devcode.la
OBJETIVOS
www.devcode.la
1. Comprender los conceptos claves de Redux.
2. Aprender a implementar un arquitectura de datos escalable con Angular.
3. Implementar Redux + Angular.
4. Aprender a definir estados globales para la aplicación.
BENEFICIOS
www.devcode.la
1. Arquitectura escalable de datos.
2. Mayor control en el flujo de datos.
3. Programación Funcional.
4. Control de estados.
5. Estado global e immutable
MÓDULOS
www.devcode.la
Módulo 1: Introducción
Módulo 2: Ideas clave de Redux
Módulo 3: Redux + Angular
Módulo 4: Proyecto
REQUISITOS
www.devcode.la
- Conocimiento previo en Angular.
- VsCode
- Goolge Chrome
- Angular CLI
¡COMENCEMOS!
www.devcode.la
ARQUITECTURA DE DATOS
www.devcode.la
MODEL-VIEW-CONTROLLER
www.devcode.la
MODEL-VIEW-COLLECTION
www.devcode.la
VIEW-VIEWMODEL-MODEL
www.devcode.la
FLUX
www.devcode.la
www.devcode.la
¿POR QUÉ REDUX?
www.devcode.la
FRONTEND ACTUAL
www.devcode.la
Controlar el estado
- Respuestas del servidor
- Datos en cache
- Datos locales
- Estados de la UI
FRONTEND ACTUAL
www.devcode.la
"En cierto punto, ya no se entiende que esta pasando en la aplicación ya que perdiste control sobre el cuándo, el por qué y el cómo de su estado"
FRONTEND ACTUAL
www.devcode.la
Redux intenta hacer predecibles las mutaciones del estado
- Store = La única fuente de la verdad
- Actions = El estado es de solo lectura
- Reducers = Los cambios los realizan acciones puras
FRONTEND ACTUAL
www.devcode.la
¿REDUX JUNTO CON RX?
www.devcode.la
RX = manejar la complejidad de aplicaciones asíncronas
CONCEPTOS CLAVE DE REDUX
www.devcode.la
STATE
www.devcode.la
{
todos: [{
text: 'Aprender redux',
completed: true
}, {
text: 'Visitar nicobytes.com',
completed: false
}],
visibilityFilter: 'SHOW_COMPLETED'
}
ACTIONS
www.devcode.la
{ type: 'ADD_TODO', text: 'Ir a nadar a la piscina' }
{ type: 'TOGGLE_TODO', index: 1 }
{ type: 'SET_VISIBILITY_FILTER', filter: 'SHOW_ALL' }
REDUCERS
www.devcode.la
REDUCERS
www.devcode.la
function visibilityFilter(state = 'SHOW_ALL', action) {
if (action.type === 'SET_VISIBILITY_FILTER') {
return action.filter;
} else {
return state;
}
}
REDUCERS
www.devcode.la
function todos(state = [], action) {
switch (action.type) {
case 'ADD_TODO':
return state.concat([{ text: action.text, completed: false }]);
case 'TOGGLE_TODO':
return state.map((todo, index) =>
action.index === index ?
{ text: todo.text, completed: !todo.completed } :
todo
)
default:
return state;
}
}
LOS TRES PRINCIPIOS
www.devcode.la
Redux puede ser descrito en tres principios fundamentales
ÚNICA FUENTE DE LA VERDAD
www.devcode.la
El estado de toda tu aplicación esta almacenado en un árbol guardado en un único store.
www.devcode.la
https://css-tricks.com/learning-react-redux/
www.devcode.la
console.log(store.getState())
/* Imprime
{
visibilityFilter: 'SHOW_ALL',
todos: [
{
text: 'Considerar usar Redux',
completed: true
},
{
text: 'Mantener todo el estado en un solo árbol',
completed: false
}
]
}
*/
EL ESTADO ES DE SOLO LECTURA
www.devcode.la
La única forma de modificar el estado es emitiendo una acción, un objeto describiendo que ocurrió.
www.devcode.la
store.dispatch({
type: 'COMPLETE_TODO',
index: 1
});
store.dispatch({
type: 'SET_VISIBILITY_FILTER',
filter: 'SHOW_COMPLETED'
});
LOS CAMBIOS SE REALIZAN EN FUNCIONES PURAS
www.devcode.la
Para especificar como el árbol de estado es transformado por las acciones, se utilizan reducers puros.
REDUCERS
www.devcode.la
PROYECTO
www.devcode.la
- Sin Angular
- Sin ngrx
- Solo ts y redux
www.devcode.la
www.devcode.la
mkdir todos-redux
www.devcode.la
{
"name": "todos-redux",
"version": "1.0.0",
"description": "",
"author": "",
"license": "MIT",
"devDependencies": {
"ts-node": "3.3.0",
"typescript": "2.4.2"
},
"dependencies": {
"redux": "3.7.2"
}
}
package.json
www.devcode.la
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"removeComments": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"noEmitHelpers": true,
"sourceMap": true,
"lib": [
"es2016",
"dom"
]
},
"compileOnSave": false,
"buildOnSave": false
}
tsconfig.json
www.devcode.la
npm install
www.devcode.la
import { createStore } from 'redux';
console.log("Compile!!!")
index.ts
www.devcode.la
./node_modules/.bin/ts-node index.ts
run
¿QUÉ ES UN REDUCER?
www.devcode.la
PROYECTO
www.devcode.la
www.devcode.la
www.devcode.la
REDUCER
- Debe retornar el mismo tipo de data en el que es definido el reducer
- Por defecto debe retornar el estado original
- Debería recibir un estado inicial
- Crear un nuevo estado
www.devcode.la
interface Action{
type: string;
payload?: any;
}
ACTION
www.devcode.la
interface Reducer<T>{
(state: T, action: Action): T;
}
REDUCER
IMPLEMENTANDO ACTIONS
www.devcode.la
www.devcode.la
La única forma de modificar el estado es emitiendo una acción, un objeto describiendo que ocurrió
www.devcode.la
interface Action{
type: string;
payload?: any;
}
www.devcode.la
if(action.type === 'INCREMENT'){
return state + 1;
}
if(action.type === 'DECREMENT'){
return state - 1;
}
www.devcode.la
switch(action.type){
case 'INCREMENT':
return state + 1;
case 'DECREMENT':
return state - 1;
default:
return state;
}
www.devcode.la
switch(action.type){
case 'INCREMENT':
return state + 1;
case 'DECREMENT':
return state + 1;
case 'PLUS':
return state + action.payload;
default:
return state;
}
www.devcode.la
GUARDANDO NUESTRO ESTADO
www.devcode.la
www.devcode.la
www.devcode.la
{
todos: [{
text: 'Aprender redux',
completed: true
}, {
text: 'Visitar nicobytes.com',
completed: false
}],
visibilityFilter: 'SHOW_COMPLETED'
}
www.devcode.la
class Store<T>{
private state:T;
constructor(
private reducer: Reducer<T>,
initState: T
){
this.state = initState;
}
}
www.devcode.la
getState(): T{
return this.state;
}
www.devcode.la
dispatch(action: Action): void{
this.state = this.reducer(this.state, action);
}
www.devcode.la
let store = new Store<number>(reducer, 0);
www.devcode.la
store.dispatch({type: 'INCREMENT'});
www.devcode.la
console.log(store.getState());
IMPLEMENTANDO REDUX Y SUBSCRIBE
www.devcode.la
www.devcode.la
import {
Action,
Reducer,
createStore,
Store
} from 'redux';
www.devcode.la
interface PlusAction extends Action{
payload: number;
}
www.devcode.la
let reducer: Reducer<number> = (state: number = 0, action: Action)=>{
switch(action.type){
case 'INCREMENT':
return state + 1
case 'DECREMENT':
return state - 1
case 'PLUS':
return state + (<PlusAction>action).payload;
default:
return state;
}
}
www.devcode.la
let store: Store<number> =
createStore<number>(reducer);
www.devcode.la
console.log(store.getState());
www.devcode.la
store.dispatch(...)
www.devcode.la
store.subscribe(()=>{
console.log(store.getState());
})
www.devcode.la
¿QUÉ ES NGRX?
www.devcode.la
Reactive Extensions for Angular
www.devcode.la
www.devcode.la
ngrx/platform
www.devcode.la
Crear proyecto
ng new counter-app-ngrx
www.devcode.la
Instalar ngrx/store
npm install @ngrx/store --save
DEFINIR LAS ACCIONES
www.devcode.la
www.devcode.la
www.devcode.la
let reducer: Reducer<number> = (state: number = 0, action: Action) =>{
if(action === null) return state;
switch(action.type){
case 'INCREMENT':
return state + 1;
case 'DECREMENT':
return state - 1;
case 'PLUS':
return state + (<PlusAction>action).payload;
default:
return state;
}
}
www.devcode.la
import { Action } from '@ngrx/store';
export const INCREMENT = '[Counter] increment';
export const DECREMENT = '[Counter] decrement';
export const PLUS = '[Counter] plus';
export const RESET = '[Counter] reset';
export interface PlusAction extends Action{
payload: number;
}
DEFINIR EL REDUCER
www.devcode.la
www.devcode.la
let reducer: Reducer<number> = (state: number = 0, action: Action) =>{
if(action === null) return state;
switch(action.type){
case 'INCREMENT':
return state + 1;
case 'DECREMENT':
return state - 1;
case 'PLUS':
return state + (<PlusAction>action).payload;
default:
return state;
}
}
www.devcode.la
counter.reducer.ts
- El estado
- Su reducer
DEFINIR EL ESTADO DE LA APP
www.devcode.la
www.devcode.la
export interface AppState{
counter: number;
}
www.devcode.la
app.reducer.ts
- El estado
- Su reducer
www.devcode.la
StoreModule.forRoot(rootReducer),
Implementar el estado en la app
www.devcode.la
Leer estado desde un componente
www.devcode.la
Memoization
this.store.select()
www.devcode.la
Enviar acciones desde un componente
IMPLEMENTADO EN COMPONENTES
www.devcode.la
Redux DevTools Extension
www.devcode.la
www.devcode.la
Actions Creator
www.devcode.la
PROYECTO
www.devcode.la
www.devcode.la
PROYECTO
www.devcode.la
CREANDO LA ESTRUCTURA REDUX
www.devcode.la
www.devcode.la
ng new todo-app-ngrx --sytle scss
www.devcode.la
npm install @ngrx/store --save
npm install @ngrx/store-devtools --save
www.devcode.la
www.devcode.la
CREANDO COMPONENTES
www.devcode.la
www.devcode.la
- TodoComponent
- TodoListComponent
- NewTodoComponent
- FooterComponent
AGREGAR UNA TAREA
www.devcode.la
LISTAR TAREAS
www.devcode.la
ELIMINAR UNA TAREA
www.devcode.la
TOGGLE DE UNA TAREA
www.devcode.la
EDITAR DE UNA TAREA
www.devcode.la
AGREGANDO ESTILOS DE TODOMVC
www.devcode.la
www.devcode.la
npm install todomvc-common --save
npm install todomvc-app-css --save
www.devcode.la
@import '~todomvc-common/base.css';
@import '~todomvc-app-css/index.css';
FOOTER COMPONENT
www.devcode.la
SELECTORS
www.devcode.la
FILTERS
www.devcode.la
CREANDO RUTAS
www.devcode.la
SELECTOR PARA TAREAS
www.devcode.la
DEPLOY
www.devcode.la
www.devcode.la
CREAR PROYECTO
www.devcode.la
INSTALAR FIREBASE CLI
www.devcode.la
www.devcode.la
firebase init
ng build --target=production --base-href /
firebase deploy
COSAS POR HACER
www.devcode.la
www.devcode.la
https://github.com/DevcodeInc/Curso-de-Angular-4-y-Redux
www.devcode.la
- Limpiar todas las tareas hechas
- Toggle pero de todas las tareas
- Persistencia
www.devcode.la
https://github.com/nicobytes/todo-app-ngrx/
www.devcode.la
Un largo camino
www.devcode.la
GRACIAS...
Curso de Angular 4 y Redux
By devcodela
Curso de Angular 4 y Redux
Curso de Angular 4 y Redux
- 1,757