We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
一般使用了中间件的 redux 初始化是下面这样的
function configureStore(initialState) { return { ...createStore( reducer, initialState, applyMiddleware(middleware1, middleware2, middleware3) ) }; } const store = configureStore({});
redux 中间件是一个函数,形式
const middleware1 = store => next => action => { console.log("before", 1); next(action); console.log("after", 1); }; const middleware2 = store => next => action => { console.log("before", 2); next(action); console.log("after", 2); }; const middleware3 = store => next => action => { console.log("before", 3); next(action); console.log("after", 3); };
需要做到
保证每一个中间件内的 store 引用都是最新的,并且是同一个
连接起来。执行一次 dispatch,会依次执行每一个中间件
代码解释
function applyMiddleWare(...middlerWares) { return createStore => (...args) => { const store = createStore(...args); let dispatch = () => {}; const middlerWareAPI = { dispatch: action => dispatch(action), getState: () => store.getState }; const chain = middlerWares.map(middleWare => chain(middlerWareAPI)); dispatch = chain.reduce((f, g) => (...args) => f(g(...args)))( store.dispatch ); return { ...store, dispatch }; }; }
从上面可以看到,一个中间件函数要最后完成,需要再执行前经过两次的初始化(分别传入 store 和 next 方法),然后到最后的调用
const chain = middlerWares.map(middleWare => chain(middlerWareAPI));
将store两个方法传递给中间件,所有中间件内都是同一份store
store
dispatch
// 这里其实就是compoose的实现 dispatch = chain.reduce((f, g) => (...args) => f(g(...args)))(store.dispatch); // 等价于类似 下面的形式 dispatch = middleWare1(middleWare2(middleWare3(dispatch)));
我们知道,经过第一步的初始化,对于middleWare1函数,可见next参数就是指向了middleWare2(dispatch)。只有我们的next调用了才会执行后面的中间件。而到了最后一个中间件middleWare3,它的next参数就是 redux 对应的dispatch函数了。从而最终把我们的action派发到store中去。然后调用栈依次返回。就像一个剥洋葱一样的东西。
middleWare1
next
middleWare2(dispatch)
middleWare3
action
所以如果我们把开头的 3 个中间件组合起来运行的话,
输出是
before 1 before 2 before 3 经过reducer // reducer中的log测试 after 3 after 2 after 1
经过上面的代码,我们还可以发现applyMiddleWare其实也是一个高阶函数。applyMiddleware(middleware1, middleware2, middleware3)执行后,是一个接收createStore参数的函数。在createStore里面又是如何操作的。源码:
applyMiddleWare
applyMiddleware(middleware1, middleware2, middleware3)
createStore
function createStore(reducer, preloadedState, enhancer) { // .....enhancer就是上面提到的 applyMiddleware(middleware1, middleware2, middleware3)返回结果 if (typeof enhancer !== "undefined") { return enhancer(createStore)(reducer, preloadedState); } // ....
其实就是把原始的createStore再传进入,进行创建store。返回一个更牛逼的store,这个store其实只是重写了dispatch方法。
1、 中间件内部必须调用next方法。才能调用下一个中间件并且到达 action
2、中间件内部如果调用了dispatch(重写后的)。不加处理就会死循环,相当于这个洋葱剥到中间又开始剥了。
这就提到一个大名鼎鼎的库redux-thunk。它的源码里面就是使用了这个dispatch
redux-thunk
function createThunkMiddleware(extraArgument) { return ({ dispatch, getState }) => next => action => { if (typeof action === "function") { return action(dispatch, getState, extraArgument); } return next(action); }; } const thunk = createThunkMiddleware(); thunk.withExtraArgument = createThunkMiddleware; export default thunk;
redux-thunk相信都很熟悉,一般用于处理编写异步逻辑下。它的源码更是牛逼。只有十几行。从上面可以看出它也是一个中间件,它的逻辑就是允许你dispatch一个函数,当你 dispatch 一个函数的时候,就直接执行它,并传入了dispatch(注意这个 是 dispatch 不是 前面中间件提到的 next)和getState方法
getState
const fetchApi = (...args) => (dispatch, getState) => { setTimeout(() => { dispatch({ type: "xx", payload: "good" }); }, 7000); }; dispatch(fetchApi("xxx"));
通过前面的分析,传进thunk内的dispatch参数就是经过包装的dispatch,所以当我们去分发一个同步的普通action的时候,它又能经过我们的其余普通中间件逻辑的处理了
thunk
redux的applyMiddleWare函数和redux-thunk。代码很简短,却隐藏着大智慧
redux
The text was updated successfully, but these errors were encountered:
No branches or pull requests
一般使用了中间件的 redux 初始化是下面这样的
redux 中间件是一个函数,形式
需要做到
保证每一个中间件内的 store 引用都是最新的,并且是同一个
连接起来。执行一次 dispatch,会依次执行每一个中间件
代码解释
从上面可以看到,一个中间件函数要最后完成,需要再执行前经过两次的初始化(分别传入 store 和 next 方法),然后到最后的调用
将
store
两个方法传递给中间件,所有中间件内都是同一份store
dispatch
一次就执行所有的中间件我们知道,经过第一步的初始化,对于
middleWare1
函数,可见next
参数就是指向了middleWare2(dispatch)
。只有我们的next
调用了才会执行后面的中间件。而到了最后一个中间件middleWare3
,它的next
参数就是 redux 对应的dispatch
函数了。从而最终把我们的action
派发到store
中去。然后调用栈依次返回。就像一个剥洋葱一样的东西。所以如果我们把开头的 3 个中间件组合起来运行的话,
输出是
经过上面的代码,我们还可以发现
applyMiddleWare
其实也是一个高阶函数。applyMiddleware(middleware1, middleware2, middleware3)
执行后,是一个接收createStore
参数的函数。在createStore
里面又是如何操作的。源码:其实就是把原始的
createStore
再传进入,进行创建store
。返回一个更牛逼的store
,这个store
其实只是重写了dispatch
方法。通过上面一堆分析,有几个结论了:
1、 中间件内部必须调用
next
方法。才能调用下一个中间件并且到达 action2、中间件内部如果调用了
dispatch
(重写后的)。不加处理就会死循环,相当于这个洋葱剥到中间又开始剥了。那么问题来了,
dispatch
什么时候用呢?这就提到一个大名鼎鼎的库
redux-thunk
。它的源码里面就是使用了这个dispatch
redux-thunk
相信都很熟悉,一般用于处理编写异步逻辑下。它的源码更是牛逼。只有十几行。从上面可以看出它也是一个中间件,它的逻辑就是允许你dispatch
一个函数,当你 dispatch 一个函数的时候,就直接执行它,并传入了dispatch
(注意这个 是 dispatch 不是 前面中间件提到的 next)和getState
方法通过前面的分析,传进
thunk
内的dispatch
参数就是经过包装的dispatch
,所以当我们去分发一个同步的普通action
的时候,它又能经过我们的其余普通中间件逻辑的处理了redux
的applyMiddleWare
函数和redux-thunk
。代码很简短,却隐藏着大智慧The text was updated successfully, but these errors were encountered: