背景
这两天在学习redux,一直比较困惑在在dispatch action的时候是如何触发reducer的状态转移的,所以今晚好好研究了一下
redux管理状态
整个状态树store是通过createStore创建的createStore方法接收reducer函数和初始化的数据(currentState),并将这2个参数并保存在store中。
action和reducer的绑定
在redux中触发状态转移一般是通过
dispatch(action(text));
或者
actions.action(text);
但是在action()中并没有指定redux,所以action是怎么调用redux状态转移的呢?
解释
实际上reducer函数的名字并没有什么用,只是为了指定子reducer的名字,便于生成rootReducer的时候使用,以及生成初始的state。
而action与reducer之间的绑定是通过action.type来实现的,同时不同的reducer只要带有相同 type 属性的都会执行。
实例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| import { combineReducers } from 'redux'; import todoApp from './todos'; import { ADD_TODO } from '../constants/ActionTypes'; const initilState = [ { text: 'Use Redux', completed: false, id: 0 } ]; function test(state = initilState, action) { switch (action.type) { case ADD_TODO: let id = state.reduce((maxId, currTodo) => { return Math.max(currTodo.id, maxId); }, -1) + 1; return [ { text: action.text, completed: true, id: id }, ...state ]; break; default: return state; } } const rootReducer = combineReducers({ todoApp, test }); export default rootReducer;
|
上面例子中定义了一个todoApp的reducer,并且添加了一个test的reducer,都有相同的action.type为ADD_TODO
。
最后调试发现产生了两个storeState,并且case ADD_TODO
都执行了。
后记
今天在做异步请求数据的时候发现几个redux的小技巧
reducer中利用相同的action.type进行处理
由于相同的action.type都会在触发action的时候执行,因此可以利用action.type做类似分支的效果,见如下代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| const initPosts = { isFetching: false, didInvalidate: false, items: [] }; function posts(state = initPosts, action) { switch (action.type) { case RECEIVE_POSTS: return Object.assign({}, state, { isFetching: false, didInvalidate: false, items: action.posts, lastUpdated: action.receivedAt }) break; default: return state; } } function postsByReddit(state = {}, action) { switch (action.type) { case RECEIVE_POSTS: case REQUEST_POSTS: return Object.assign({}, state, { [action.reddit]: posts(state[action.reddit], action) }) default: return state } } const rootReducer = combineReducers({ selectedReddit, postsByReddit, })
|
需要进行状态的改变可以利用componentWillReceiveProps
1 2 3 4 5 6
| componentWillReceiveProps(nextProps) { if (nextProps.selectedReddit !== this.props.selectedReddit) { const {selectedReddit, actions} = nextProps; actions.fetchPosts(selectedReddit); } }
|