Single Source of Truth
可预测性
纯函数更新 Store
function todo (state = [], action) {
switch (action.type) {
case 'ADD_TODO':
return state.concat([{text: action.text, completed: false}]);
case 'TOGGLE_TODO':
return state.map((todo, index) => {
if (index === action.index) {
return Object.assign({}, todo, {
completed: !todo.completed
});
}
return todo;
});
default:
return state;
}
}
const store = createStore(reducer);
getState()
dispatch(action)
subscribe(listener)
描述行为的数据结构
{
type: 'ADD_TODO',
text: 'Learn about actions'
}
本质是个函数,接收 state 和 action,返回新的 state
function todoApp (state = initialState, action) {
switch (action.type) {
case 'ADD_TODO':
return Object.assign({}, state, {
todos: [
...state.todos,
{
text: action.text,
completed: false
}
]
});
case 'TOGGLE_TODO':
return Object.assign({}, state, {
todos: state.todos.map((todo, index) => {
if (index === action.index) {
return Object.assign({}, todo, {
completed: !todo.completed
});
}
return todo;
})
});
default:
return state;
}
}
export default function todos (state = [], action) {
switch (action.type) {
case 'ADD_TODO':
return [
...state,
{
text: action.text,
completed: false
}
];
default:
return state;
}
}
export default function counter (state = 0, action) {
switch (action.type) {
case 'INCREMENT':
return state + 1;
case 'DECREMENT':
return state - 1;
default:
return state;
}
}
import { combineReducers } from 'redux';
import todos from './todos';
import counter from './counter';
export default combineReducers({
todos,
counter
});
写法 1:
function addTodoWithDispatch (text) {
const action = {
type: 'ADD_TODO',
text
};
dispatch(action);
}
写法 2:
dispatch(addTodo(text));
dispatch(completeTodo(index));
bindActionCreators 写法:
const boundAddTodo = text => dispatch(addTodo(text));
const boundCompleteTodo = index => dispatch(completeTodo(index));
import { connect } from 'react-redux';
class SidePanel extends Component {}
function mapStateToProps (state) {
return {
nextgen: state.nextgen,
router: state.router
};
}
function mapDispatchToProps (dispatch) {
return {
actions: bindActionCreators({
...actions
}, dispatch),
};
}
export default connect(mapStateToProps, mapDispatchToProps)(SidePanel);
复制🤏
connect 工作原理:高阶组件
“标准”形式 Redux Action 的问题:
更好的组织:单个 action 和 reducer 放在同一个文件
// counterPlusOne.js
import { COUNTER_PLUS_ONE } from './constants';
export function counterPlusOne() {
return {
type: COUNTER_PLUS_ONE
};
}
export function reducer (state, action) {
switch (action.type) {
case COUNTER_PLUS_ONE:
return {
...state,
counter: state.counter + 1
};
default:
return state;
}
}
为什么采用不可变数据?
如何操作不可变数据?
原生:{...}
, Object.assign()
const state = {
filter: 'completed',
todos: [
'Learn React'
]
};
const newState = {
...state,
todos: [
...state.todos,
'Learn Redux'
]
};
const newState2 = Object.assign({}, state, {
todos: [
...state.todos,
'Learn Redux'
]
});
immutability-helper,适合更新节点层级较深的复杂情况
import update from 'immutability-helper';
const state = {
filter: 'completed',
todos: [
'Learn React'
]
};
const newState = update(state, {
todos: {
$push: ['Learn Redux']
}
});
immer
import produce from 'immer';
const state = {
filter: 'completed',
todos: [
'Learn React'
]
};
const newState = produce(state, draftState => {
draftState.todos.push('Learn Redux');
});