by Gerard Sans (@gerardsans)
Laptops shiny and ready by 9:45
Instructions bit.ly/iwd17-mastering-state
9:30 Welcome
Instructions and setup
Slides
Practice, Q&A
11:30 Wrapping up
1x WebStorm year license (£45 each)
twit to participate in raffle
@angular_zone #iwd2017
800
700
// index.html
<my-app ng-version="4.0.0-rc.2">
<div>
<h2>Hello Angular 4! 👋</h2>
</div>
</my-app>
DATA CLIENTS
GraphQL
Firebase
ngrx
Redux
STATE MANAGEMENT
Dan Abramov
source: blog
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
// function foo(x) { return x+1; }
let foo = x => x+1;
// pure function
foo(1); // 2
foo(1); // 2
let flag = false;
let foo = x => {
flag = !flag; // side effect
return flag ? x+1: 0;
}
// not pure function
foo(1); // 2
foo(1); // 0
DATA CLIENTS
GraphQL
Firebase
ngrx
Redux
STATE MANAGEMENT
Rob Wormald
5.0.3
1
2
3
Stream
//Observable constructor
let simple$ = Rx.Observable.create(observer => {
try {
//pushing values
observer.next(1);
observer.next(2);
observer.next(3);
//complete stream
observer.complete();
}
catch(e) {
//error handling
observer.error(e);
}
});
/*
a$ ---1---2---3|
*/
let a$ = Rx.Observable.of(1,2,3);
let subscription = a$.subscribe({
next: x => console.log(x),
error: x => console.log('#'),
complete: () => console.log('|')
});
let subscription = twits$.subscribe(
twit => feed.push(twit),
error => console.log(error),
() => console.log('done')
);
setTimeout(() => subscription.unsubscribe(), 5000);
Rx.Observable.of(1)
.subscribe({
next: x => console.log(x),
complete: () => console.log('3')
});
console.log('2');
// a) 1 2 3
// b) 2 1 3
// c) 1 3 2
// d) 3 2 1
<app>
<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>
</app>
import { App } from './app';
import { StoreModule } from "@ngrx/store";
import { rootReducer } from './rootReducer';
@NgModule({
imports: [
BrowserModule,
StoreModule.provideStore(rootReducer)
],
declarations: [ App ],
bootstrap: [ App ]
})
export class AppModule {}
platformBrowserDynamic().bootstrapModule(AppModule);
@Component({
template:
`<todo *ngFor="let todo of todos | async">{{todo.text}}</todo>`
})
export class App implements OnDestroy {
todos: Observable<Todo>;
constructor(
private _store: Store<TodosState>
) {
this.todos = _store.let(
state$ => state$.select(s => s.todos);
);
}
private ngOnDestroy(){
this.todos.unsubscribe();
}
}
// add new todo
{
type: ADD_TODO,
id: 1,
text: "learn redux",
completed: false
}
const initialState = [];
const todos = (state = initialState, action:Action) => {
switch (action.type) {
case TodoActions.ADD_TODO:
return state.concat({
id: action.id,
text: action.text,
completed: action.completed });
default: return state;
}
}
// {
// todos: [], <-- todos reducer will mutate this key
// currentFilter: 'SHOW_ALL'
// }
const currentFilter = (state = 'SHOW_ALL', action: Action) => {
switch (action.type) {
case TodoActions.SET_CURRENT_FILTER:
return action.filter
default: return state;
}
}
// {
// todos: [],
// currentFilter: 'SHOW_ALL' <-- filter reducer will mutate this key
// }
import { combineReducers } from '@ngrx/store';
const combinedReducer = combineReducers({
todos: todos,
currentFilter: currentFilter
});
export rootReducer = (state, action) => combinedReducer(state, action);
{
todos: [{
id: 1,
text: "learn redux",
completed: false
}],
currentFilter: 'SHOW_ALL'
}
// {
// todos: [], <-- we start with no todos
// currentFilter: 'SHOW_ALL'
// }
// <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(
private _store: Store<TodosState>,
private todoActions:TodoActions
) { }
private onTodoClick(id){
this._store.dispatch(this.todoActions.toggleTodo(id));
}
}
demo