本文作者:IMWeb chenxd1996 原文出处:IMWeb社区 未经同意,禁止转载
Redux源码分析
熟悉React的同学应该对于Redux都比较熟悉,Redux可以对多个组件间的共享数据进行统一管理,解决了组件间数据传递的问题。它的源码实现其实非常简单,接下来我们就来学习一下。
redux源码传送门
redux源码分为7个部分
- utils
- applyMiddleware
- bindActionCreator
- combineReducers
- compose
- createStore
- index
下面我们就来分别分析这几部分的代码:
1. index
这是redux的入口文件。
代码语言:javascript复制import createStore from './createStore'
import combineReducers from './combineReducers'
import bindActionCreators from './bindActionCreators'
import applyMiddleware from './applyMiddleware'
import compose from './compose'
import warning from './utils/warning'
import __DO_NOT_USE__ActionTypes from './utils/actionTypes'
...
export {
createStore,
combineReducers,
bindActionCreators,
applyMiddleware,
compose,
__DO_NOT_USE__ActionTypes
}
2. createStore
这个文件定义createStore函数,用来创建Redux中的store。
最终返回的是一个对象
代码语言:javascript复制 return {
dispatch,
subscribe,
getState,
replaceReducer,
[$$observable]: observable
}
这里主要看下subscribe、dispatch的实现。
1. subscribe:
代码语言:javascript复制 function subscribe(listener) {
if (typeof listener !== 'function') {
throw new Error('Expected the listener to be a function.')
}
if (isDispatching) {
throw new Error(
'You may not call store.subscribe() while the reducer is executing. '
'If you would like to be notified after the store has been updated, subscribe from a '
'component and invoke store.getState() in the callback to access the latest state. '
'See https://redux.js.org/api-reference/store#subscribe(listener) for more details.'
)
}
let isSubscribed = true
ensureCanMutateNextListeners() // 深复制currentListers为nextListeners数组
nextListeners.push(listener)
return function unsubscribe() {
if (!isSubscribed) {
return
}
if (isDispatching) {
throw new Error(
'You may not unsubscribe from a store listener while the reducer is executing. '
'See https://redux.js.org/api-reference/store#subscribe(listener) for more details.'
)
}
isSubscribed = false
ensureCanMutateNextListeners()
const index = nextListeners.indexOf(listener)
nextListeners.splice(index, 1)
}
}
2. dispatch
代码语言:javascript复制 function dispatch(action) {
if (!isPlainObject(action)) {
throw new Error(
'Actions must be plain objects. '
'Use custom middleware for async actions.'
)
}
if (typeof action.type === 'undefined') {
throw new Error(
'Actions may not have an undefined "type" property. '
'Have you misspelled a constant?'
)
}
if (isDispatching) {
throw new Error('Reducers may not dispatch actions.')
}
try {
isDispatching = true
// 通过reducer函数,获得新的state
currentState = currentReducer(currentState, action)
} finally {
isDispatching = false
}
// 执行listener函数
const listeners = (currentListeners = nextListeners)
for (let i = 0; i < listeners.length; i ) {
const listener = listeners[i]
listener()
}
return action
}
3. combineReducers
顾名思义就是将多个reducer合成一个reducer。传入的reducer是一个对象,对象的键值是reducer的名称。
代码语言:javascript复制 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 (typeof reducers[key] === 'function') {
finalReducers[key] = reducers[key]
}
}
const finalReducerKeys = Object.keys(finalReducers)
let unexpectedKeyCache
if (process.env.NODE_ENV !== 'production') {
unexpectedKeyCache = {}
}
...
return function combination(state = {}, action) {
...
let hasChanged = false
const nextState = {}
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)
...
nextState[key] = nextStateForKey
hasChanged = hasChanged || nextStateForKey !== previousStateForKey
}
return hasChanged ? nextState : state
}
}
4. bindActionCreator
返回一个或多个函数,这些函数执行后dispatch对应的action。
代码语言:javascript复制 function bindActionCreator(actionCreator, dispatch) {
return function() {
return dispatch(actionCreator.apply(this, arguments))
}
}
export default function bindActionCreators(actionCreators, dispatch) {
if (typeof actionCreators === 'function') {
return bindActionCreator(actionCreators, dispatch)
}
...
const keys = Object.keys(actionCreators)
const boundActionCreators = {}
for (let i = 0; i < keys.length; i ) {
const key = keys[i]
const actionCreator = actionCreators[key]
if (typeof actionCreator === 'function') {
boundActionCreators[key] = bindActionCreator(actionCreator, dispatch)
}
}
return boundActionCreators
}
5. compose
例如compose(a, b, c) => (...args) => a(b(c(...args)))
代码语言:javascript复制 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)))
}
6. applyMiddleware
用来使用中间件,中间件的其实就是对dispatch进行包装,用来处理各种action,例如redux-thunk。
代码语言:javascript复制 export default function applyMiddleware(...middlewares) {
return createStore => (...args) => {
const store = createStore(...args)
// 在应用中间件的过程中不可以dispatch。
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
}
}
}
怎么样,redux源码还是非常清晰简单的吧,如果还有疑惑,推荐去看官网文档帮助理解一些概念哦。
redux中文文档