redux中reducer与action的绑定

背景

这两天在学习redux,一直比较困惑在在dispatch action的时候是如何触发reducer的状态转移的,所以今晚好好研究了一下

redux管理状态

Alt
整个状态树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);
}
}