-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
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源码解析 #6
Comments
utils
actionTypes.js
const randomString = () => //"2.f.g.d.o.8"
Math.random()
.toString(36) //36进制
.substring(7) //从index为7开始取
.split('')
.join('.')
const ActionTypes = {
INIT: `@@redux/INIT${randomString()}`,
REPLACE: `@@redux/REPLACE${randomString()}`,
PROBE_UNKNOWN_ACTION: () => `@@redux/PROBE_UNKNOWN_ACTION${randomString()}`
}
export default ActionTypes ActionTypes有三种
isPlainObject.js
export default function isPlainObject(obj) {
if (typeof obj !== 'object' || obj === null) return false
let proto = obj
while (Object.getPrototypeOf(proto) !== null) {
//普通的对象while循环结束后proto的值是:Object.prototype,通过Object.create(null)生成的对象proto的值是:null
proto = Object.getPrototypeOf(proto)
}
return Object.getPrototypeOf(obj) === proto
} 通过 function someFunction(arg) {
if (arg instanceof Array) {
// ... operate on the array
}
} 因为两段代码所处的 warning.js
export default function warning(message) {
/* eslint-disable no-console */
if (typeof console !== 'undefined' && typeof console.error === 'function') {
console.error(message)
}
/* eslint-enable no-console */
try {
throw new Error(message)
} catch (e) {} // eslint-disable-line no-empty
} |
applyMiddleware.jsexport default function applyMiddleware(...middlewares) {
return createStore => (...args) => {
// 此时...arg=(reducer, preloadedState)
const store = createStore(...args)
// 此时 store={dispatch,subscribe,getState,replaceReducer,[$$observable]: observable}
let dispatch = () => {...} //防止在构建期间dispatch
const middlewareAPI = {
getState: store.getState,
dispatch: (...args) => dispatch(...args)
}
// chain=[next=>action=>....]
const chain = middlewares.map(middleware => middleware(middlewareAPI))
/**
* 给每个中间件加入middlewareAPI
* 如 chian = [middleware1, middleware2, middleware3]
*/
dispatch = compose(...chain)(store.dispatch)
/**
* 通过compose函数传入chain一层层增强dispatch
* dispatch = compose(...chain)(store.dispatch),即执行 middleware1(middleware2(middleware3(store.dispatch)))
*/
return {
...store,
dispatch //通过中间件增强之后的dipatch
}
}
} 常用方法 执行之后返回:
精简下来之后看着就清晰了。
|
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))) 函数式编程,整体代码很短...
每次循环返回一个函数 则:第一次循环: 第二次循环: |
bindActionCreators.js
bindActionCreators之后的action boundActionCreators={
action1:function() {return dispatch(actionCreator.apply(this, arguments))},
action2:function() {return dispatch(actionCreator.apply(this, arguments))},
action3:function() {return dispatch(actionCreator.apply(this, arguments))},
} function bindActionCreator(actionCreator, dispatch) { //此函数就是返回一个function,并且帮你dispatch
return function() {
return dispatch(actionCreator.apply(this, arguments))
}
}
export default function bindActionCreators(actionCreators, dispatch) {
if (typeof actionCreators === 'function') {
/**
* 如果是function则返回一个
* function() {
return dispatch(actionCreator.apply(this, arguments))
}
actionCreator应当接收参数并返回一个action
*/
return bindActionCreator(actionCreators, dispatch)
}
if (typeof actionCreators !== 'object' || actionCreators === null) {...}
const boundActionCreators = {}
for (const key in actionCreators) {
const actionCreator = actionCreators[key] //遍历拿到dispatch函数
if (typeof actionCreator === 'function') {
boundActionCreators[key] = bindActionCreator(actionCreator, dispatch)
}
}
return boundActionCreators
} 不使用 function actions(dispatch) {
return {
onIncrement: () => dispatch(increment())
};
} 使用 let actions = {
addItem: ()=>({type: types.ADD_ITEM,paload})
}
bindActionCreators(actions, dispatch); |
combineReducers.js
export default function combineReducers(reducers) {
const reducerKeys = Object.keys(reducers)
const finalReducers = {}
for (let i = 0; i < reducerKeys.length; i++) {
const key = reducerKeys[i]
if (process.env.NODE_ENV !== 'production') {
if (typeof reducers[key] === 'undefined') {...}
}
if (typeof reducers[key] === 'function') { //过滤掉不是function的
finalReducers[key] = reducers[key]
}
}
const finalReducerKeys = Object.keys(finalReducers)
// This is used to make sure we don't warn about the same
// 这是用来确保我们不会发出同样的警告
// keys multiple times.
let unexpectedKeyCache
if (process.env.NODE_ENV !== 'production') {
unexpectedKeyCache = {}
}
let shapeAssertionError
try {
assertReducerShape(finalReducers) //遍历执行两次数组内的reducer,对返回值进行判断
} catch (e) {
shapeAssertionError = e
} 上面一系列操作,干了几件事:
assertReducerShape
function assertReducerShape(reducers) {
Object.keys(reducers).forEach(key => {
const reducer = reducers[key]
const initialState = reducer(undefined, { type: ActionTypes.INIT })
if (typeof initialState === 'undefined') {
throw new Error(
`Reducer "${key}" returned undefined during initialization. ` +
`If the state passed to the reducer is undefined, you must ` +
`explicitly return the initial state. The initial state may ` +
`not be undefined. If you don't want to set a value for this reducer, ` +
`you can use null instead of undefined.`
/**
* 在初始化期间返回undefined。
* 如果传递给reducer的state未定义,则必须显式返回初始状态。
* 初始状态不能是未定义的。如果不想为此reducer设置值,可以使用NULL而不是undefined。`
*/
)
}
if (
typeof reducer(undefined, {
type: ActionTypes.PROBE_UNKNOWN_ACTION()
}) === 'undefined'
) {
throw new Error(
`Reducer "${key}" returned undefined when probed with a random type. ` +
`Don't try to handle ${ActionTypes.INIT} or other actions in "redux/*" ` +
`namespace. They are considered private. Instead, you must return the ` +
`current state for any unknown actions, unless it is undefined, ` +
`in which case you must return the initial state, regardless of the ` +
`action type. The initial state may not be undefined, but can be null.`
/**
* 使用随机类型探测时,reducer“${key}”返回undefined。
* 不要试图在“redux/*”名称空间中处理${ActionTypes.INIT}或其他操作。
* 他们被认为是私人的。相反,您必须返回任何未知操作的当前状态,除非未定义,
* 在这种情况下,无论操作类型如何,都必须返回初始状态。初始状态不能未定义,但可以为空。
*/
)
}
})
} 通过该函数对类型的判断之后, 再返回看剩下的 return function combination(state = {}, action) {//作为createStore中reducer参数
if (shapeAssertionError) {...}
if (process.env.NODE_ENV !== 'production') {
const warningMessage = getUnexpectedStateShapeWarningMessage(
state,
finalReducers,
action,
unexpectedKeyCache
)
if (warningMessage) {
warning(warningMessage)
}
}
let hasChanged = false //判断state是否改变
const nextState = {}
/**
* 每次dispatch的时候就会遍历执行所有的reducer
*/
for (let i = 0; i < finalReducerKeys.length; i++) {
const key = finalReducerKeys[i]
const reducer = finalReducers[key]
const previousStateForKey = state[key]
const nextStateForKey = reducer(previousStateForKey, action)
if (typeof nextStateForKey === 'undefined') {
const errorMessage = getUndefinedStateErrorMessage(key, action)
throw new Error(errorMessage)
}
nextState[key] = nextStateForKey
hasChanged = hasChanged || nextStateForKey !== previousStateForKey
}
return hasChanged ? nextState : state //改变了则返回改变之后的state,否则返回之前的state
}
getUnexpectedStateShapeWarningMessage
function getUnexpectedStateShapeWarningMessage(
inputState,
reducers,
action,
unexpectedKeyCache
) {
const reducerKeys = Object.keys(reducers)
const argumentName =
action && action.type === ActionTypes.INIT //判断是初始化时reducer,还是之后的reducer
? 'preloadedState argument passed to createStore'//传递给createStore的preloadedState参数
: 'previous state received by the reducer'//reducer接收的先前状态
if (reducerKeys.length === 0) {//Store没有有效的reducer。确保传递给comineReducers的参数是一个值为Reducers的对象}
if (!isPlainObject(inputState)) {...}
/**
* 获取state上未被reducer处理的状态的键值unexpectedKeys,并将其存入cache值中。
*/
const unexpectedKeys = Object.keys(inputState).filter(
//如果reducer的属性中没有state,并且unexpectedKeyCache中没有对应的值
key => !reducers.hasOwnProperty(key) && !unexpectedKeyCache[key]
)
unexpectedKeys.forEach(key => {
unexpectedKeyCache[key] = true
})
/**
* 检测是否为内置的replace action,因为当使用store的replaceReducer时会自动触发该内置action,
* 并将reducer替换成传入的,此时检测的reducer和原状态树必然会存在冲突,
* 所以在这种情况下检测到的unexpectedKeys并不具备参考价值,将不会针对性的返回抛错信息,反之则会返回。
*/
if (action && action.type === ActionTypes.REPLACE) return
if (unexpectedKeys.length > 0) {
return (
`Unexpected ${unexpectedKeys.length > 1 ? 'keys' : 'key'} ` +
`"${unexpectedKeys.join('", "')}" found in ${argumentName}. ` +
`Expected to find one of the known reducer keys instead: ` +
`"${reducerKeys.join('", "')}". Unexpected keys will be ignored.`
)
}
} getUndefinedStateErrorMessagefunction getUndefinedStateErrorMessage(key, action) {
const actionType = action && action.type
const actionDescription =
(actionType && `action "${String(actionType)}"`) || 'an action'
return (
`Given ${actionDescription}, reducer "${key}" returned undefined. ` +
`To ignore an action, you must explicitly return the previous state. ` +
`If you want this reducer to hold no value, you can return null instead of undefined.`
)
} |
redux源码解析
目录:
createStore.js
export default function createStore(reducer, preloadedState, enhancer)
暴露
createStore
函数,返回:createStore大致有三种使用:
接下来就逐个分析一下~
变量声明和类型判断
类型判断,除了排除特定的type之外,还有另外一个目的就是,满足参数灵活。
getState
subscribe
如果在调用dispatch时订阅或取消订阅,则不会对当前正在进行的dispatch产生任何影响。但是,下一个dispatch调用(无论是否嵌套)将使用订阅列表的最新快照。
listener
是否是function
,否则报错dispatch
状态,true
则报错,在reducer中不能调用。ensureCanMutateNextListeners()
,判断当前监听队列是否和临时监听队列是否相同引用,如果相同则通过slice复制出来一份,赋值给nextListeners,此举为了不混淆当前的监听队列。unsubscribe
依旧触发ensureCanMutateNextListeners
,然后找到对应的listener(在subscribe
函数时形成闭包)在数组中的index,删除。currentListeners = null
(较老的版本没有这句) 这句没太搞懂为什么这么写,有大佬明白的麻烦给说下,谢了~dispatch
扁平对象
type
是否为undefined
,是则报错dispatch
,是则报错true
,通过reducer
处理之后或者 最新的state
监听:
将
nextListeners
直接赋值给currentListeners
,统一当前的监听列表,然后遍历执行监听函数replaceReducer
将
reducer
替换之后,dispatch
一下,更新state
。一般不会用到observable
这部分用到了一个包symbol-observable感兴趣的可以去看下
最后
dispatch({ type: ActionTypes.INIT })
创建存储时,将dispatch 'INIT',以便每个reducer返回其初始状态。这有效地填充了初始state tree。
The text was updated successfully, but these errors were encountered: