前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Redux源码分析

Redux源码分析

作者头像
IMWeb前端团队
发布2019-12-03 17:38:39
3110
发布2019-12-03 17:38:39
举报
文章被收录于专栏:IMWeb前端团队IMWeb前端团队

本文作者: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中文文档

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018-09-04 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Redux源码分析
  • 1. index
  • 2. createStore
    • 1. subscribe:
      • 2. dispatch
      • 3. combineReducers
      • 4. bindActionCreator
      • 5. compose
      • 6. applyMiddleware
      相关产品与服务
      消息队列 TDMQ
      消息队列 TDMQ (Tencent Distributed Message Queue)是腾讯基于 Apache Pulsar 自研的一个云原生消息中间件系列,其中包含兼容Pulsar、RabbitMQ、RocketMQ 等协议的消息队列子产品,得益于其底层计算与存储分离的架构,TDMQ 具备良好的弹性伸缩以及故障恢复能力。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档