Using Redux
and Angular 2
by Gerard Sans (@gerardsans)
Google Developer Expert
Master of Ceremonies
International Speaker
Angular 2 Trainer
Community Leader
800
500
Blogger
Redux
Dan Abramov
Main Features
- Unidirectional data flow
- Single Immutable State
- New states are created without side-effects
Unidirectional data flow
Single Immutable State
- Helps tracking changes by reference
- Improved Performance
- Enforce by convention or using a library. Eg: Immutable.js
Immutable by Convention
- New array using Array Methods
- map, filter, slice, concat
- Spread operator (ES6) [...arr]
- New object using Object.assign (ES6)
immutable List and Map
let selectedUsers = Immutable.List([1, 2, 3]);
let user = Immutable.Map({ id: 4, username: 'Spiderman'}):
let newSelection = selectedUsers.push(4, 5, 6); // [1, 2, 3, 4, 5, 6];
let newUser = user.set('admin', true);
newUser.get('admin') // true
immutable Record
var ABRecord = Immutable.Record({a:1, b:2});
var myRecord = new ABRecord({b:3});
myRecord.get('b') // 3
myRecordWithoutB = myRecord.remove('b')
myRecordWithoutB.get('b') // 2
myRecord.b // 3
myRecord.b = 5 // throws Error
myRecord.set('b', 5)
myRecord.b // 5
Reducers
- Reducers create new states in response to Actions applied to the current State
- Reducers are pure functions
- Don't produce side-effects
- Composable
Example: pure function
// function foo(x) { return x+1; }
let foo = x => x+1;
// pure function
foo(1); // 2
foo(1); // 2
Example: side-effect
let flag = false;
let foo = x => {
flag = !flag; // side effect
return flag ? x+1: 0;
}
// not pure function
foo(1); // 2
foo(1); // 0
Middlewares
- Sit between Actions and Reducers
- Used for logging, storage and asynchronous operations
- Composable
Angular 2
Features
- Latest Web Standards
- Simple
- Lightning fast
- Works everywhere
Components Tree
Components Tree
<root>
<add-todo>
<input><button>Add todo</button>
</add-todo>
<todo-list>
<ul>
<todo id="0" completed="false"><li>buy milk</li></todo>
</ul>
</todo-list>
<filters>
Show: <filter-link><a>All</a><filter-link> ...
</filters>
</root>
Redux Setup
import { App } from './app';
import { createStore } from 'redux';
const appStore = createStore(rootReducer);
@NgModule({
imports: [ BrowserModule ],
declarations: [
App, ...APP_DECLARATIONS
],
providers: [
{ provide: 'AppStore', useValue: appStore },
TodoActions
],
bootstrap: [ App ]
})
export class AppModule { }
platformBrowserDynamic().bootstrapModule(AppModule);
Adding a new Todo
- Component subscribe to the Store
- Component dispatches ADD_TODO action
- Store executes rootReducer
- Store notifies Component
- View updates
Subscribing to the Store
@Component({
template:
`<todo *ngFor="let todo of todos">{{todo.text}}</todo>`
})
export class TodoList implements OnDestroy {
constructor(@Inject('AppStore') private appStore: AppStore){
this.unsubscribe = this.appStore.subscribe(() => {
let state = this.appStore.getState();
this.todos = state.todos;
});
}
private ngOnDestroy(){
this.unsubscribe();
}
}
ADD_TODO Action
// add new todo item
{
type: ADD_TODO,
id: 1,
text: "learn redux",
completed: false
}
todos Reducer
const todos = (state = [], action) => {
switch (action.type) {
case TodoActions.ADD_TODO:
return state.concat({
id: action.id,
text: action.text,
completed: action.completed });
default: return state;
}
}
currentFilter Reducer
const currentFilter = (state = 'SHOW_ALL', action) => {
switch (action.type) {
case 'SET_CURRENT_FILTER':
return action.filter
default: return state
}
}
rootReducer
import { combineReducers } from 'redux'
export const rootReducer = combineReducers({
todos: todos,
currentFilter: currentFilter
});
New State
{
todos: [{
id: 1,
text: "learn redux",
completed: false
}],
currentFilter: 'SHOW_ALL'
}
Stateless Todo Component
// <todo id="1" completed="true">buy milk</todo>
@Component({
inputs: ['id', 'completed'],
template: `
<li (click)="onTodoClick(id)"
[style.textDecoration]="completed?'line-through':'none'">
<ng-content></ng-content>
</li>`,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class Todo {
constructor(
@Inject('AppStore') private appStore: AppStore,
private todoActions: TodoActions){ }
private onTodoClick(id){
this.appStore.dispatch(this.todoActions.toggleTodo(id));
}
}
Change Detection
Change Detection
Redux Dev Tools
Features
- Save/Restore State
- Live Debugging
- Time travel
- Dispatch Actions
Libraries
- Angular 2 bindings for Redux
- Built on top of Redux
- Compatible w/ DevTools and existing ecosystem
- Re-implementation of Redux on top Angular 2 and RxJS 5
- ngrx suite: store, effects, router, db
- Not compatible w/ DevTools and existing ecosystem
Why use Redux?
Main Benefits
- Simplified Development
- Avoids complex dependencies
- Great Performance
- Developer Experience
Thanks!
Questions
Using Redux and Angular 2
By Gerard Sans
Using Redux and Angular 2
Redux is an architecture made famous by Facebook and React. It is based on Flux so it provides a solid base to create complex applications. In this talk we are going to use a basic application to showcase Redux while using Angular 2.
- 3,316