React-Redux 源码解析 一(createStore)

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

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

一般而言,我查看一个库的源代码,首先回查看对应方法的参数,其次是对应的 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)》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

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

The Web Application Hacker's Handbook

The Web Application Hacker's Handbook

Dafydd Stuttard、Marcus Pinto / Wiley / 2011-9-27 / USD 50.00

The highly successful security book returns with a new edition, completely updated Web applications are the front door to most organizations, exposing them to attacks that may disclose personal infor......一起来看看 《The Web Application Hacker's Handbook》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

MD5 加密
MD5 加密

MD5 加密工具

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器