Redux and Angular 1.x
Bob Bijvoet
Front-end Chapter Lead
Building Blocks 1
Problems with application state today
Looking at the future
A predictable state container for JavaScript apps.
Single source of truth
The state of your whole application is stored in an object tree within a single store.
State is read-only
The only way to mutate the state is to emit an action, an object describing what happened.
Changes are made with pure functions
To specify how the state tree is transformed by actions, you write pure reducers.
Pure function
- Given the same input, will always return the same output.
- Produces no side effects.
- Relies on no external state.
Store
The place where all your application state lives
//State
{
items:[],
done:true
}
Actions
Tells store that something happened and that the store should update itself in response.
//Action
{
type:'SOME_ACTION',
payload:{}
}
//Example
{
type:'ADD_TO_CART',
payload:{
id:1,
price:42
}
}
Reducers
Responsible for mutating the store state when actions are dispatched
reducer(state, action) {
switch (action.type) {
case 'SOME_ACTION':
//Mutate state
}
return state;
}
reducer(state, action) {
switch (action.type) {
case 'ADD_TO_CART':
cart.push(action.payload)
break;
}
return state;
}
Middleware
Provides the ability to create functions that extend the library.
Container
- Are concerned with how things work.
- May contain both presentational and container components.
- Provide the data and behavior to presentational or other container components.
- Are often stateful, as they tend to serve as data sources.
Presentational
- Are concerned with how things look.
- Don’t specify how the data is loaded or mutated.
- Rarely have their own state (when they do, it’s UI state rather than data).
Component architecture
Component architecture
Sprint app
State
State
sprint:{
number: 0,
burnedPoints: 0,
done:false
};
stories:[{
id:'1'
points:1,
description:'',
done:false
}]
Actions
{
type: 'STORY_DONE',
payload: {
id: story.id,
points:story.points
}
};
{
type:'SPRINT_DONE'
};
Actions
function storyDone(story) {
return {
type: 'STORY_DONE',
payload: {
id: story.id,
points:story.points
}
};
}
Action creator
Reducer
//Stories reducer
case 'STORY_DONE':
var story = state.find(function(story) {
return story.id === action.payload.id;
});
if (story) {
story.done = true;
}
//Sprint reducer
case 'STORY_DONE':
state.burnedPoints += action.payload.points;
break;
case 'SPRINT_DONE':
state.done = true;
Reducer
Middleware
Middleware
Promise middleware
//Action
{
type: 'FETCH_SPRINT',
payload: {
promise: mainService.getSprint()
}
//Results in actions:
//FETCH_SPRINT_PENDING
//FETCH_SPRINT_FULFILLED or FETCH_SPRINT_REJECTED
//Stories reducer
case 'FETCH_SPRINT_FULFILLED':
state = action.payload.stories;
Middleware
- thunk middleware
- logging middleware
$ngRedux
Redux bindings for Angular 1.x
Application source
Benefits
- One place for state
- One place for app logic
- Clear list of actions
- Asynchronous state representation
- Powerful middleware and easy debugging
- Easily testable
Testing
Goodies
Let's start hacking
Switch to ing-assignment branch
https://github.com/bobbijvoet/ng-redux-session
ng-redux session at ING
By Bob Bijvoet
ng-redux session at ING
- 1,447