基础
Array.prototype.reduce
//类似的核心思想
const initState = '';
const actions = ['a', 'b', 'c'];
const newState = actions.reduce(
( (prevState, action) => prevState + action ),
initState
);
//action: actions;
//state: initState,newState;
//reducer: (prevState, action) => prevState + action //计算
Action
- 描述有什么事情发生了;
{
type: 'ADD_TODO',
text: 'Build Redux app'
}
- 改变
State
只能通过actions
, 使用store.dispatch()
。并且,每一个action
都必须是Javascript Plain Object
; - 为保证状态保存、回放、Undo 之类的功能可以被实现,
action
必须是可以被序列化的因此,不能包含如函数调用这样的不可序列化字段; -
type
是必须要有的字符串属性; 建议文档; - 好的结构中应该每次
action
传需要的数据而不是整个
{
type: SET_VISIBILITY_FILTER,
filter: SHOW_COMPLETED
}
Action Creator
- 事实上,创建
action
对象更多地是通过一个创建函数;
function addTodo(text) {
return {
type: ADD_TODO,
text
};
}
//触发
dispatch(addTodo(text));
-
dispatch
可以直接来自store.dispatch
;
handleClick() {
// Works! (but you need to grab store somehow)
store.dispatch(addTodo('Fix the issue'));
}`
-
react-redux
中可以通过connect(mapStateToProps,mapDispatchToProps)(Counter)
;-
mapStateToProps
函数通过返回一个映射对象selector
,指定了 Store/State属性映射到React Component
的this.props
的情况;
-
class AddTodo extends Component {
handleClick() {
// Works!
this.props.dispatch(addTodo('Fix the issue'));
}
....
}
//将dispatch和state放入props
export default connect(select)(AddTodo);
- 或者结合
bindActionCreators(actionCreators, dispatch);
import * as CounterActions from '../actions/counter';
function mapStateToProps(state) {
return {
counter: state.counter
};
}
function mapDispatchToProps(dispatch) {
return bindActionCreators(CounterActions, dispatch);
}
export default connect(mapStateToProps, mapDispatchToProps)(Counter); //可以直接添加actionCreators
//调用
<button onClick={this.props.addTodo}/>add</button>
Reducers
- 描述事情发生后
state
如何改变;
更新成员
为了确保
State
的消费者在判断数据是否变化时,只要简单地进行引用比较避免Deep Equal
的遍历,需要确保State
中每个节点都是不可改变的;在
Reducer
中更新State
成员需要增加
//对象
let counters = {
faves: 0,
forward: 20,
}
// this creates a brand new copy overwriting just that key
counters = {...counters, faves: counters.faves + 1}
//数组; 调换顺序,可以改变增加的位置;
let todos = [
{ id: 1, text: 'have lunch'}
]
todos = [...todos, { id: 2, text: 'buy a cup of coffee'} ]
- 删除
//数组
let users = [...];
users = users.filter(user=> user.id !== find.id)
- 由于更新数据的差异:如对于数组型
react:state
操作后,会同时更新操作位置之后的数据;而redux则只会更新操作位置的数据;
同步执行
-
Reducer
的执行是同步的; - 在给定
initState
以及一系列的actions
,都应该得到相同的newState
;
分割reduce
-
Reducer
和action.type
是多对多的关系;
export default function counter(state = 0, action) {
switch (action.type) {
case INCREMENT_COUNTER:
return state + 1;
case DECREMENT_COUNTER:
return state - 1;
default:
return state;
}
}
- 在程序变多时可以使用
combineReducers({field1: reducerForField1,....})
来管理- 每个
reducerForField1
将仅仅获得State.field1
的值,而看不到State
下的其他字段的内容; - 响应的返回结果也会被合并到对应的
State
字段中;
- 每个
import { combineReducers } from 'redux';
const todoAppReducer = combineReducers({
visibilityFilter: visibilityFilterReducer
todos: todosReducer
});
//
visibilityFilterReducer 仅仅负责处理 State.visibilityFilter 字段的状态
- 注意使用
combineReducers
的前提是,每一个被组合的Reducer
仅仅和State
的一部分数据相关; - 如果需要消费其他
State
字段,那还是需要在大switch
中为特定处理函数传入整个State
;
function todoAppReducer(state = initialState, action) {
switch (action.type) {
case FAVE_ALL_ITEMS:
return Object.assign({}, state, faveThemAll(state));
default:
return state;
}
}
Store
- 维护应用程序状态的对象;
- 构造
Store
对象,仅需要提供一个Reducer
函数;
import { combineReducers, createStore } from 'redux';
import * as reducers from './reducers';
const todoAppReducer = combineReducers(reducers);
const store = createStore(todoAppReducer); // Line 5
store.dispatch({type: 'ADD_TODO', text: 'Build Redux app'});
- 可以在
createStore
的时候为Store
指定一个初始状态;
const store = createStore(reducers, window.STATE_FROM_SERVER);
方法
-
store.getState()
: 获取最近的内部状态对象; -
store.dispatch(action)
: 将一个action
对象发送给reducer
; -
store.subscribe(listener)
:订阅状态的变化;并不推荐使用, 可以搭配Observable
模式的程序,react
中不建议;
Provider Component
- 通过
Provider Component
来设定connect
从哪里获得store
对象;
React.render(
<Provider store={store}>
{() => <MyRootComponent />} //react 0.14: <MyRootComponent />
</Provider>,
rootEl
);
主要流程
- 设置
redecers
,分片的话使用redux: combineReducers
; - 创建
store
,使用redux: createStore
,传入reducers
; - 在特定的组件/顶层组件绑定状态和
dispatch
,使用react-redux: connet
,传入状态映射selector
; - 将
store
关联到绑定后的特定/顶层组件,使用react-resuc: Provider
; - 设置
actions
,并在组件想要调用的地方触发this.props.dispatch()
,自动更新state
;
其他
- 在绑定组件时使用
redux: bindActionCreators
,connect
传入第二参数,直接将dispatch(actions)
传入组件ptops
; //注意此时action
则必须是Action Creator
; - 在创建
store
时使用redux: applyMiddleware
先传入中间件,再创建
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import reducer from '../reducers';
const createStoreWithMiddleware = applyMiddleware(
thunk
)(createStore);
export default function configureStore(initialState) {
const store = createStoreWithMiddleware(reducer, initialState);
return store;
}
//
const store = configureStore();