React-Redux 源码解析 一(createStore)

栏目: 服务器 · 发布时间: 6年前

内容简介:一般而言,我查看一个库的源代码,首先回查看对应方法的参数,其次是对应的通过查看源码,发现查看源码的开始部分,我们发现

一般而言,我查看一个库的源代码,首先回查看对应方法的参数,其次是对应的 return ,然后再看代码的具体实现。

通过查看源码,发现 createStore 方法返回了一个对象, 该对象共暴露出了五个方法,四个常用的方法:

return {
    dispatch,
    subscribe,
    getState,
    replaceReducer,
    [$$observable]: observable
  }
复制代码

查看源码的开始部分,我们发现 createStore 可以传入两个三个参数:

export default function createStore(reducer, preloadedState, enhancer) 
复制代码

其中第一个参数 reducer 是必须要传递的而且必须是一个函数,不然Redux回报一场

if (typeof reducer !== 'function') {
    throw new Error('Expected the reducer to be a function.')
  }
复制代码

如果传递了第二个参数 preloadedState ,而且第二个参数不是一个 function , 则将 preloadedState 保存在内部变量 currentState 中, 也就是我们给 State 的默认状态

如果 preloadedState 是一个function , 则将preloadedState 赋值给 enhancer

if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') {
    enhancer = preloadedState
    preloadedState = undefined
  }

  if (typeof enhancer !== 'undefined') {
    if (typeof enhancer !== 'function') {
      throw new Error('Expected the enhancer to be a function.')
    }
    // 运行enhancer, 一般enhancer 就是一组中间件
    return enhancer(createStore)(reducer, preloadedState)
  }

  if (typeof reducer !== 'function') {
    throw new Error('Expected the reducer to be a function.')
  }
复制代码

该方法中保存了三个重要的变量:

let currentReducer = reducer
let currentState = preloadedState
let currentListeners = []
复制代码
  1. currentReducer 保存了所有的Reducer
  2. currentState 将状态数据都保存在这里,也是Redux 操作数据的唯一对象
  3. currentListeners 会保存对Redux State 订阅的监听者

我们已经知道了Redux能控制的如上三个主要内部变量了, 接下拉我们会 根据 createStore 暴露出来的五个方法,来学习怎么去操作这三个变量

return {
    dispatch,
    subscribe,
    getState,
    replaceReducer,
    [$$observable]: observable
  }
复制代码

dispatch(去掉验证代码)

function dispatch(action) {
      try {
      isDispatching = true
      // 调用Reduce 对action 进行处理,每次传入原始的state.返回更新后的states
      currentState = currentReducer(currentState, action)
    } finally {
      isDispatching = false
    }
    // 对订阅者进行处理
    const listeners = (currentListeners = nextListeners)
    for (let i = 0; i < listeners.length; i++) {
      const listener = listeners[i]
      listener()
    }

    return action
  }
复制代码

首先需要传递一个 action 参数来告诉需要做的操作对象,action 只能是一个Object, 而且必须包含 type 字段

if (!isPlainObject(action)) {
      throw new Error(
        'Actions must be plain objects. ' +
        'Use custom middleware for async actions.'
      )
    }

    if (typeof action.type === 'undefined') { // 必须包含**Type**
      throw new Error(
        'Actions may not have an undefined "type" property. ' +
        'Have you misspelled a constant?'
      )
    }
复制代码

我们会调用内部变量 currentReducer 去处理发起的对应的 action

currentState = currentReducer(currentState, action)
复制代码

我们会发现 currentReducer 其实是一个 function , 而且需要两个参数: currentState , action .

currentReducer返回的值赋值给 currentState , 由 createStore 传入参数的分析得知, preloadedState 只能是要给Object, 所以 currentReducer function 返回的是要给Object.

从这一行代码我们可以总结得到:

reducer 其实就是一个函数,根据action 对 currentState 进行处理,并且返回新的currentState 的函数

const listeners = (currentListeners = nextListeners)
    for (let i = 0; i < listeners.length; i++) {
      const listener = listeners[i]
      listener()
    }
复制代码

由上面一段代码我们可以得知,在更新 state , 需要去遍历执行所有的监听者(listener),让监听者得知state变更的信息

subscribe(订阅)

subscribe顾名思义就是消息订阅的意思

function subscribe(listener) {
    let isSubscribed = true

    ensureCanMutateNextListeners()
    nextListeners.push(listener)

    return function unsubscribe() {
      if (!isSubscribed) {
        return
      }   
      isSubscribed = false
      ensureCanMutateNextListeners()
      const index = nextListeners.indexOf(listener)
      nextListeners.splice(index, 1)
    }
  }
复制代码

很简单的一段代码, 传入的参数listener 就是一个订阅者方法,

nextListeners.push(listener)
复制代码

将listener 保存在内部变量数组中。返回一个unsubscribe方法, 用来取消订阅

nextListeners.splice(index, 1) // 只要从数组中删除listener 就是取消订阅了
复制代码

getState(获取状态)

function getState() {
    return currentState
  }
复制代码

非常简单,就是返回内部变量 currentState

replaceReducer(替换reducer)

function replaceReducer(nextReducer) {
    currentReducer = nextReducer
    dispatch({ type: ActionTypes.REPLACE })
  }

复制代码

就是替换当前的reducer.

总结

  1. 首先我们需要调用 createStore 方法创建一个 store
let store = createStore(reducer, preloadedState)
复制代码

reducer 是一个function, 而且必须要 传递两个参数,第一个是state, 第二个是一个action

  1. 利用相关事件触发store.dispatch(action)去变更状态

这个action 必须要有 type 属性

  1. 订阅状态变更store.subscribe(listener)
  2. 在listener中去获取最新state(store.getState()),然后做去相应的处理
React-Redux 源码解析 一(createStore)
可以在 Redux examples

下载代码运行查看效果.


以上所述就是小编给大家介绍的《React-Redux 源码解析 一(createStore)》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

游戏编程算法与技巧

游戏编程算法与技巧

【美】Sanjay Madhav / 刘瀚阳 / 电子工业出版社 / 2016-10 / 89

《游戏编程算法与技巧》介绍了大量今天在游戏行业中用到的算法与技术。《游戏编程算法与技巧》是为广大熟悉面向对象编程以及基础数据结构的游戏开发者所设计的。作者采用了一种独立于平台框架的方法来展示开发,包括2D 和3D 图形学、物理、人工智能、摄像机等多个方面的技术。《游戏编程算法与技巧》中内容几乎兼容所有游戏,无论这些游戏采用何种风格、开发语言和框架。 《游戏编程算法与技巧》的每个概念都是用C#......一起来看看 《游戏编程算法与技巧》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码