INTRODUCTION TO REDUX
- Open a browser on any laptop, tablet or smartphone
- Go to slido.com
- Enter the event code #LC149
PREDICTABLE
STATE CONTAINER
FOR JAVASCRIPT APPLICATION
DATA
CONSISTENCY
PREDICTABLE
DEBUGGABILITY
3 PILLARS OF REDUX
3 PILLARS OF REDUX
-
SINGLE SOURCE OF TRUTH
-
STATE IS READ ONLY
-
CHANGES ARE MADE WITH PURE FUNCTIONS
SINGLE SOURCE OF TRUTH
STATE IS READ-ONLY
CHANGES ARE MADE WITH PURE FUNCTIONS
// pure functions
function square(x) {
return x * x;
}
function squareAll(items) {
return items.map(square);
}
// impure functions
let TWO = 2;
function square(x) {
updateDb(x);
return x * TWO;
}
function squareAll(items) {
for(let i=0; i<items.length; i++) {
items[i] = square(items[i]);
}
return items;
}
3 PILLARS OF REDUX
-
SINGLE SOURCE OF TRUTH
-
STATE IS READ ONLY
-
CHANGES ARE MADE WITH PURE FUNCTIONS
require("redux")
Writing Reducers
Avoiding array mutations
push(), pop(), unshift(), splice()
// adding an item
// NO
function addItem(items, item) {
items.push(item);
return items;
}
// YES
function addItem(items, item) {
return items.concat([item]);
}
function addItem(items, item) {
return [...items, item];
}
// removing an item
// NO
function removeItem(items, index) {
items.splice(index);
return items;
}
// YES
function removeItem(items, index) {
return items.slice(0, index)
.concat(item.slice(index + 1));
}
function removeItem(items, index) {
return [
...items.slice(0, index),
...items.slice(index + 1)
];
}
// increment an item
// NO
function incrementItem(items, index) {
items[index]++;
return items;
}
// YES
function incrementItem(items, index) {
return items.slice(0, index)
.concat([items[index] + 1])
.concat(item.slice(index + 1));
}
function incrementItem(items, index) {
return [
...items.slice(0, index),
items[index] + 1,
...items.slice(index + 1)
];
}
Avoiding object mutations
// setting a value
// NO
function toggleTodo(todo) {
todo.completed = !todo.completed;
return todo;
}
// YES
function toggleTodo(todo) {
return {
id: todo.id,
text: todo.text,
completed: !todo.completed,
};
}
function toggleTodo(todo) {
return Object.assign({}, todo, { completed: !todo.completed });
}
// ES6
function toggleTodo(todo) {
return {
...todo,
completed: !todo.completed,
};
}
Write a reducer: Adding Todo
Write a reducer:
Change Visibility
Write a reducer:
Toggle Todo
function reducer(state = INITIAL_STATE, action) {
switch(action.type) {
case 'TOGGLE_TODO': {
return {
...state,
todos: state.todos.map(todo => {
if (todo.id === action.id) {
return {
...todo,
done: !todo.done,
};
} else {
return todo;
}
});
}
}
}
}
function reducer(state = INITIAL_STATE, action) {
switch(action.type) {
case 'TOGGLE_TODO': {
return {
...state,
todos: state.todos.map(todo => {
if (todo.id === action.id) {
return {
...todo,
done: !todo.done,
};
} else {
return todo;
}
});
}
}
}
}
function todoReducer(todo, action) {
switch(action.type) {
case 'TOGGLE_TODO':
if (todo.id === action.id) {
return {
...todo,
done: !todo.done,
};
} else {
return todo;
}
}
}
function todosReducer(state = INITIAL_STATE, action) {
switch(action.type) {
case 'EDIT_TODO':
case 'TOGGLE_TODO':
return {
...state,
todos: state.todos.map(todo => todoReducer(todo, action)),
}
}
}
{
"todos": Todo[],
"visibiltiyFilter": "SHOW_ALL" |
"SHOW_ACTIVE" |
"SHOW_COMPLETED",
}
function todosReducer(state = [], action) {
// ...
return state;
}
function visibilityFilterReducer(state = 'SHOW_ALL', action) {
// ...
return state;
}
function reducer(state, action) {
return {
todos: todosReducer(state, action),
visibilityFilter: visibilityFilterReducer(state, action),
}
}
combineReducers
const reducer = combineReducer({
visibilityFilter: visibilityFilterReducer,
todos: todosReducer,
});
Redux + React
require('react-redux')
connect(
mapStateToProps,
mapDispatchToProps
) (Component)
connect(
(state) => {
return {
// state props
items: state.items,
};
},
(dispatch) => {
return {
// dispatch props
toggleItem: (index) =>
dispatch({ type: 'TOGGLE', index: index })
};
}
) (Component)
// itemsSelector can be reused
function itemsSelector(state) {
return state.items;
}
connect(
(state) => {
return {
// state props
items: itemsSelector(state),
};
},
(dispatch) => {
return {
// dispatch props
toggleItem: (index) =>
dispatch({ type: 'TOGGLE', index: index })
};
}
) (Component)
selector
}
Let mapStateToProps Reshape the Data from the Store
mapStateToProps Functions Should Be Fast
Return Values Determine If Your Component Re-Renders
Only Return New Object References If Needed
connect(
(state) => {
return {
// state props
items: state.items,
};
},
(dispatch) => {
return {
// dispatch props
toggleItem: (index) =>
dispatch({ type: 'TOGGLE', index: index })
};
}
) (Component)
connect(
(state) => {
return {
// state props
items: state.items,
};
},
{
// dispatch props
toggleItem: (index) =>
({ type: 'TOGGLE', index: index })
}
) (Component)
// can reuse this action
function toggleAction(index) {
return { type: 'TOGGLE', index: index };
}
connect(
(state) => {
return {
// state props
items: state.items,
};
},
{
// dispatch props
toggleItem: toggleAction,
}
) (Component)
actionCreator
}
SUMMARY
Redux + React
ACTION
REDUCER
STORE
SELECTOR
REACT COMPONENTS
1 WAY DATA FLOW
ACTION
REDUCER
STORE
SELECTOR
REACT COMPONENTS
1 WAY DATA FLOW
ACTION
REDUCER
STORE
SELECTOR
REACT COMPONENTS
1 WAY DATA FLOW
ACTION
REDUCER
STORE
SELECTOR
REACT COMPONENTS
1 WAY DATA FLOW
ACTION
REDUCER
STORE
SELECTOR
REACT COMPONENTS
1 WAY DATA FLOW
ACTION
REDUCER
STORE
SELECTOR
REACT COMPONENTS
1 WAY DATA FLOW
dispatch
ACTION
REDUCER
STORE
SELECTOR
REACT COMPONENTS
1 WAY DATA FLOW
ACTION
REDUCER
STORE
SELECTOR
REACT COMPONENTS
1 WAY DATA FLOW
ACTION
REDUCER
STORE
SELECTOR
REACT COMPONENTS
1 WAY DATA FLOW
ACTION
REDUCER
STORE
SELECTOR
REACT COMPONENTS
1 WAY DATA FLOW
ACTION
REDUCER
STORE
SELECTOR
REACT COMPONENTS
1 WAY DATA FLOW
Asynchronous Redux
ACTIONS
- Requesting Action
- Request Success Action
- Request Fail Action
Redux Middleware
import { createStore, applyMiddleware } from 'redux'
const store = createStore(
reducers,
// applyMiddleware() tells createStore() how to handle middleware
applyMiddleware(
middleware1,
middleware2,
)
)
"redux-thunk"
thunk - past tense of "think"
- The New Hacker's Dictionary
Redux DevTools
Resources
Q & A
- Open a browser on any laptop, tablet or smartphone
- Go to slido.com
- Enter the event code #LC149
REDUX
By Li Hau Tan
REDUX
- 634