# Redux中间件原理与Redux-Thunk的原理
# 中间件原理
# 中间件写法
首先我们先看看怎么实现一个logger中间件
- logger.js
export default store => next => action => {
console.log('store:', store)
next(action)
console.log('action', action)
}
1
2
3
4
5
2
3
4
5
使用applyMiddleware(logger)加载中间件,从上面这个logger中间我们可以看到中间价是一个嵌套函数,三个参数分别是store,next,action
# 源码分析
- node_modules/redux/src/applyMiddleware.js
export default function applyMiddleware(...middlewares) {
return createStore => (...args) => {
const store = createStore(...args)
let dispatch = () => {
throw new Error(
`Dispatching while constructing your middleware is not allowed. ` +
`Other middleware would not be applied to this dispatch.`
)
}
const middlewareAPI = {
getState: store.getState,
dispatch: (...args) => dispatch(...args)
}
const chain = middlewares.map(middleware => middleware(middlewareAPI))
dispatch = compose(...chain)(store.dispatch)
return {
...store,
dispatch
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
整个applyMiddleware返回一个函数
const chain = middlewares.map(middleware => middleware(middlewareAPI))
1
可以看出中间件的第一个参数是middlewareAPI
dispatch = compose(...chain)(store.dispatch)
1
那么compose是干嘛的呢?
- node_modules/redux/src/compose.js
export default function compose(...funcs) {
if (funcs.length === 0) {
return arg => arg
}
if (funcs.length === 1) {
return funcs[0]
}
return funcs.reduce((a, b) => (...args) => a(b(...args)))
}
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
可以看出compose是让函数嵌套执行的方法,那么上面compose就是吧store.dispatch经过一层层的封装,那么next就是原始的dispatch,action就是我们发送的action。
所以中间件的写法其实就是对dispatch进行了一层封装。
# Redux-Thunk原理
# Redux-Thunk使用
//action types
const GET_DATA = 'GET_DATA',
GET_DATA_SUCCESS = 'GET_DATA_SUCCESS',
GET_DATA_FAILED = 'GET_DATA_FAILED';
//action creator
const getDataAction = function(id) {
return function(dispatch, getState) {
dispatch({
type: GET_DATA,
payload: id
})
api.getData(id) //注:本文所有示例的api.getData都返回promise对象
.then(response => {
dispatch({
type: GET_DATA_SUCCESS,
payload: response
})
})
.catch(error => {
dispatch({
type: GET_DATA_FAILED,
payload: error
})
})
}
}
//reducer
const reducer = function(oldState, action) {
switch(action.type) {
case GET_DATA :
return oldState;
case GET_DATA_SUCCESS :
return successState;
case GET_DATA_FAILED :
return errorState;
}
}
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
39
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
39
# Redux-Thunk源码
- node_modules/redux-thunk/lib/index.js
function createThunkMiddleware(extraArgument) {
return function (_ref) {
var dispatch = _ref.dispatch,
getState = _ref.getState;
return function (next) {
return function (action) {
if (typeof action === 'function') {
return action(dispatch, getState, extraArgument);
}
return next(action);
};
};
};
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
可以看thunk的实现十分简单,只是把dispatch作为参数传递给了action(此处action是个函数),而从上面的使用来看,在异步中按需dispatch新的action进行新的处理