redux api源码解析

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.`
      )
    }
  })
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值