index.js
/*
* This is a dummy function to check if the function name has been altered by minification.
* If the function has been minified and NODE_ENV !== 'production', warn the user.
*/
function isCrushed() {}
if (
process.env.NODE_ENV !== 'production' &&
typeof isCrushed.name === 'string' &&
isCrushed.name !== 'isCrushed'
) {
warning(
'You are currently using minified code outside of NODE_ENV === \'production\'. ' +
'This means that you are running a slower development build of Redux. ' +
'You can use loose-envify (https://github.com/zertosh/loose-envify) for browserify ' +
'or DefinePlugin for webpack (http://stackoverflow.com/questions/30030031) ' +
'to ensure you have the correct code for your production build.'
)
}
export {
createStore,
combineReducers,
bindActionCreators,
applyMiddleware,
compose
}
isCrushed
- 检查函数名是否已经被压缩(minification)
function isCrushed() {}
if(typeof isCrushed.name === 'string' && isCrushed.name !== 'isCrushed'){
//has minified
}
compose组合
- 通过reduce实现函数的连续嵌套调用
/**
* Composes single-argument functions from right to left. The rightmost
* function can take multiple arguments as it provides the signature for
* the resulting composite function.
*
* @param {...Function} funcs The functions to compose.
* @returns {Function} A function obtained by composing the argument functions
* from right to left. For example, compose(f, g, h) is identical to doing
* (...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)))
}
- 若传递的是compose(e,f,g) ,则第一次调用返回(…args) => e(f(…args))
- 第二调用,a为(…args) => e(f(…args)),b为g
- 则最终调用结果为(…args) => e(f(g(…args)))
bindActionCreators
基本用法
import {bindActionCreators} from 'redux'
const mapDispatchToProps=(dispatch)=>{
return {
xxx:bindActionCreators(xx,dispatch) xx为引入的action集合,import * as xx from '../store/actions'
}
}
调用:this.props.xxx.action名称()
- bindActionCreators将值为actionCreator的对象转化成具有相同键值的对象,但是每一个actionCreator都会被dispatch所包裹调用,因此可以直接使用,而不用dispatch显式调用
import warning from './utils/warning'
//actionCreator为传入的action,即()=>{type:'xx',...}
function bindActionCreator(actionCreator, dispatch) {
return (...args) => dispatch(actionCreator(...args))
}
export default function bindActionCreators(actionCreators, dispatch) {
//当传入的是一个action函数时
if (typeof actionCreators === 'function') {
return bindActionCreator(actionCreators, dispatch)
}
if (typeof actionCreators !== 'object' || actionCreators === null) {
throw new Error(
`bindActionCreators expected an object or a function, instead received ${actionCreators === null ? 'null' : typeof actionCreators}. ` +
`Did you write "import ActionCreators from" instead of "import * as ActionCreators from"?`
)
}
//当传入的是包含了多个action的对象
const keys = Object.keys(actionCreators)
const boundActionCreators = {}
for (let i = 0; i < keys.length; i++) {
const key = keys[i]
//获取每一个action函数
const actionCreator = actionCreators[key]
if (typeof actionCreator === 'function') {
//将action对应的key赋值一个隐式调用dipatch的函数bindActionCreator
boundActionCreators[key] = bindActionCreator(actionCreator, dispatch)
} else {
warning(`bindActionCreators expected a function actionCreator for key '${key}', instead received type '${typeof actionCreator}'.`)
}
}
//即可通过返回的对象的对应acion的key进行dispatch
return boundActionCreators
}
createStore、getState、subscribe、dispatch、replaceReducer、observable
- 生成一个应用唯一的store
import isPlainObject from 'lodash/isPlainObject'
import ?observable from 'symbol-observable'
//内置初始化的action.type
//初始化的时候(redux.createStore(reducer, initialState)时),传的action.type
export const ActionTypes = {
INIT: '@@redux/INIT'
}
export default function createStore(reducer, preloadedState, enhancer) {
//preloadedState为初始化时传入的初始值
if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') {
//如果没有传入参数enhancer,并且preloadedState的值又是一个函数的话,createStore会认为你省略了preloadedState,因此第二个参数就是enhancer
enhancer = preloadedState
preloadedState = undefined
}
if (typeof enhancer !== 'undefined') {
if (typeof enhancer !== 'function') {
throw new Error('Expected the enhancer to be a function.')
}
return enhancer(createStore)(reducer, preloadedState)
}
if (typeof reducer !== 'function') {
throw new Error('Expected the reducer to be a function.')
}
//currentReducer是用来存储当前的reducer函数。
//currentState用来存储当前store中的数据,初始化为默认的preloadedState
//currentListeners用来存储当前的监听者。
//isDispatching用来当前是否属于正在处理dispatch的阶段。
let currentReducer = reducer
let currentState = preloadedState
let currentListeners = []
let nextListeners = currentListeners
let isDispatching = false
function ensureCanMutateNextListeners() {
if (nextListeners === currentListeners) {
nextListeners = currentListeners.slice()
}
}
//获取当前store状态的唯一方法
function getState() {
return currentState
}
//用来订阅store变化的函数
function subscribe(listener) {
if (typeof listener !== 'function') {
throw new Error('Expected listener to be a function.')
}
//通过闭包,让返回的取消订阅函数只在第一次执行有效
let isSubscribed = true
//用来判断nextListeners和currentListeners是否是完全相同,然后返回值的拷贝
ensureCanMutateNextListeners()
//添加订阅者
//再nextListeners中添加是因为新添加|取消的订阅者,需要在下次dispatch时生效,而不是在currentListeners本次生效
nextListeners.push(listener)
return function unsubscribe() {
if (!isSubscribed) {
return
}
isSubscribed = false
ensureCanMutateNextListeners()
const index = nextListeners.indexOf(listener)
nextListeners.splice(index, 1)
}
}
function dispatch(action) {
//action必须是一个{type:'xx',...}类型的对象
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?'
)
}
//避免在reducer内调用dispatch,而dispatch又会调用reducer造成的死循环
if (isDispatching) {
throw new Error('Reducers may not dispatch actions.')
}
try {
isDispatching = true
//通过reducer函数来进行当前currentState
currentState = currentReducer(currentState, action)
} finally {
isDispatching = false
}
//dispatch时调用各个订阅的回调,告知store已经发生了变化
const listeners = currentListeners = nextListeners
for (let i = 0; i < listeners.length; i++) {
const listener = listeners[i]
listener()
}
//并没有将新的store作为参数传递给监听者,因为监听者函数内部可以通过调用唯一获取store的函数store.getState()获取最新的store
return action
}
//主要用户热更新reducer
function replaceReducer(nextReducer) {
if (typeof nextReducer !== 'function') {
throw new Error('Expected the nextReducer to be a function.')
}
currentReducer = nextReducer
dispatch({ type: ActionTypes.INIT })
}
//主要涉及到RxJS和响应异步Action
function observable() {
const outerSubscribe = subscribe
return {
subscribe(observer) {
if (typeof observer !== 'object') {
throw new TypeError('Expected the observer to be an object.')
}
function observeState() {
if (observer.next) {
observer.next(getState())
}
}
observeState()
const unsubscribe = outerSubscribe(observeState)
return { unsubscribe }
},
[?observable]() {
return this
}
}
}
//初始化调用
dispatch({ type: ActionTypes.INIT })
//比如我们可以调用store.dispatch、store.getState获取当前store状态
return {
dispatch,
subscribe,
getState,
replaceReducer,
[?observable]: observable
}
}
combineReducers
export default function combineReducers(reducers) {
const reducerKeys = Object.keys(reducers)
const finalReducers = {}
for (let i = 0; i < reducerKeys.length; i++) {
const key = reducerKeys[i]
//判断传入的多个reducer是否有效
if (process.env.NODE_ENV !== 'production') {
if (typeof reducers[key] === 'undefined') {
warning(`No reducer provided for key "${key}"`)
}
}
if (typeof reducers[key] === 'function') {
finalReducers[key] = reducers[key]
}
}
const finalReducerKeys = Object.keys(finalReducers)
let unexpectedKeyCache
if (process.env.NODE_ENV !== 'production') {
unexpectedKeyCache = {}
}
let shapeAssertionError
try {
assertReducerShape(finalReducers)
} catch (e) {
shapeAssertionError = e
}
return function combination(state = {}, action) {
if (shapeAssertionError) {
throw shapeAssertionError
}
if (process.env.NODE_ENV !== 'production') {
const warningMessage = getUnexpectedStateShapeWarningMessage(state, finalReducers, action, unexpectedKeyCache)
if (warningMessage) {
warning(warningMessage)
}
}
let hasChanged = false
const nextState = {}
for (let i = 0; i < finalReducerKeys.length; i++) {
const key = finalReducerKeys[i]
//遍历获取每一个reducer
const reducer = finalReducers[key]
//根据key获取每一个reducer的状态
const previousStateForKey = state[key]
//每个reducer传入action获取当前状态
const nextStateForKey = reducer(previousStateForKey, action)
//检测action.type是否错误
if (typeof nextStateForKey === 'undefined') {
const errorMessage = getUndefinedStateErrorMessage(key, action)
throw new Error(errorMessage)
}
//更新状态
nextState[key] = nextStateForKey
//判断状态是否改变
hasChanged = hasChanged || nextStateForKey !== previousStateForKey
}
//根据状态是否改变返回改变后的状态或上一次状态
return hasChanged ? nextState : state
}
}
assertReducerShape
- 判断reducers中的每一个reducer在action为{ type: ActionTypes.INIT }时是否有初始值,如果没有则会抛出异常。
- 并且会对reduer执行一次随机的action,如果没有返回,则抛出错误,告知你不要处理redux中的私有的action
- 对于未知的action应当返回当前的state。并且初始值不能为undefined但是可以是null
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.`
)
}
const type = '@@redux/PROBE_UNKNOWN_ACTION_' + Math.random().toString(36).substring(7).split('').join('.')
if (typeof reducer(undefined, { type }) === '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.`
)
}
})
}