查看源码后的记录(最近会整理下电脑里之前的一些笔记,发到csdn)
createStore
会初始化store里的state,并且添加一系列的api:
store的state只是createStore里的一个普通变量,store的初始化状态可以通过createStore
的第二个参数指定,如果没有指定,也可以通过reducer的默认参数指定,因为调用createStore的时候会dispatch一个用于init的actionType
,这个actionType是随机的,所以会设置上给reducer的state默认参数。第三个参数是一个增强器,增加store的功能,redux自带的增强器只有applyMiddleware
函数,从createStore的部分源码可以看到增强器的调用,同时会直接返回增强器的结果:
if (typeof enhancer !== 'undefined') {
if (typeof enhancer !== 'function') {
throw new Error('Expected the enhancer to be a function.')
}
return enhancer(createStore)(reducer, preloadedState)
}
增强器会接收createStore函数作为参数。
每次触发action会调用所有reducer,同时会在之后依次调用subscribe订阅的监听器。
subscribe函数将注册的监听器添加到nextListeners
队列,nextListeners
是currentListeners
的浅拷贝对象,然后返回一个unsubscribe
函数,unsubscribe
会将监听函数从nextListeners
里去除。nextListeners
作为dispatch过程中的currentListeners
一个临时列表,防止在dispatch过程中调用subscribe和unsubscribe函数造成bug。
获取store里的state:
function getState() {
if (isDispatching) { // 如果正在进行dispatch过程会报错
throw new Error(
'You may not call store.getState() while the reducer is executing. ' +
'The reducer has already received the state as an argument. ' +
'Pass it down from the top reducer instead of reading it from the store.'
)
}
return currentState // 该变量存储了store里的所有state
}
替换reducer并重置store里的state。
接收多个reducer函数(reducers对象),除了作一些校验外,就返回一个函数,该函数将接收到的state
和action
依次传递给所有的reducer,每个reducer执行后返回一个子state,最后以键值对的方式组合成最后store的完整状态
,键就是reducers对象的键,值即为对应reducer返回的子state。
接收由多个actionCreator组成的一个对象和dispatch作为参数:
bindActionCreators(actionCreators, dispatch)
// actionCreators案例:
{
creatorA: () => ({ type: 'xx' })
}
// 返回案例
{
creatorA: function() {
dispatch(creatorA.apply(this, arguments)
}
}
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.`
)
// 防止在构建中间件的时候,调用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
}
}
}
可以看到applyMiddleware
函数会返回一个闭包函数,也就是一个enhaner
,这个闭包函数返回的对象表明,使用中间件后,除dispatch
函数外的其他store属性都不变化,所以中间件的功能就是对原本的dispatch
函数进行包裹,至于新的dispatch函数功能得看compose
函数如何处理多个中间件:
// compose函数源码,compose(f, g, h)的结果:(...args) => f(g(h(...args)))
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)))
}
这么看的话,可能会绕进去,写个简单例子分析。
首先构造三个简单的中间件,一个redux中间件的结构我们可以看看redux-thunk
的源码:
function createThunkMiddleware(extraArgument) {
return ({ dispatch, getState }) => next => action => {
if (typeof action === 'function') {
// 异步action是一个函数,收到三个参数
// 第三个参数可以是一些我们自定义的api
return action(dispatch, getState, extraArgument);
}
return next(action);
};
}
const thunk = createThunkMiddleware();
thunk.withExtraArgument = createThunkMiddleware;
export default thunk;
可以得出一个redux中间件
的大致结构应该是这样(且我们应该了解中间件是拦截了action到reducer这个过程):
const middleware = ({
getState,
dispatch
}) => next => action => {
// 处理逻辑
// 处理逻辑完成后,调用next,也就是进入到下一个中间件
next(action)
}
三个简单的中间件:
// 中间件f
const middlewareF = ({
getState,
dispatch
}) => nextF => action => {
/*
* 处理中间件f的逻辑
*/
nextF(action)
}
// 中间件g
const middlewareG = ({
getState,
dispatch
}) => nextG => action => {
/*
* 处理中间件g的逻辑
*/
nextG(action)
}
// 中间件h
const middlewareH = ({
getState,
dispatch
}) => nextH => action => {
/*
* 处理中间件h的逻辑
*/
nextH(action)
}
使用applyMiddleware
处理三个中间件:
applyMiddleware(
middlewareF,
middlewareG,
middlewareH
)
当函数走到调用compose函数
处时,chain变量
应该是:
const f = nextF => action => {
/*
* 处理中间件f的逻辑
*/
nextF(action)
}
const g = nextG => action => {
/*
* 处理中间件g的逻辑
*/
nextG(action)
}
const h = nextH => action => {
/*
* 处理中间件h的逻辑
*/
nextH(action)
}
const chain = [
f,
g,
h
]
compose(...chain)
包装后返回:
(...args) => f(g(h(...args)))
再看compose(...chain)(dispatch)
的结果:
f(g(h(dispatch))) // 返回结果
// 一步步来分析,先执行h(dispatch),将h(dispatch)的结果赋值给h1
const h1 = action => {
/*
* 处理中间件h的逻辑
*/
dispatch(action)
}
// g(h(dispatch))就变成了g(h1),返回结果赋值给g1
const g1 = action => {
/*
* 处理中间件g的逻辑
*/
h1(action)
}
// 最后时f(g1),也就是f(g(h(dispatch)))解析后的结果,同是也是新的dispatch函数的结果,这样看的会清晰一点
const f1 = action => {
/*
* 处理中间件f的逻辑
*/
g1(action)
}
分析完毕后,可以看到新的dispatch函数执行,会按顺序处理各个中间件的逻辑,并且在最后一个中间件使用原来的dispatch函数
触发action。
就是对一组功能的组合,且是从右到左。
阅读redux的源码后,会发现很大一部分代码都是在对参数作校验,抛出错误等(js本身没有类型约束),核心代码其实很简洁,阅读很舒服