redux的createStore的源码,注释已经翻译成中文,至于代码,你们应该看得懂

如果看不清楚,可以查看https://segmentfault.com/a/1190000018385942

import isPlainObject from 'lodash/isPlainObject'

import $$observable from 'symbol-observable'

/**

* These are private action types reserved by Redux.

* For any unknown actions, you must return the current state.

* If the current state is undefined, you must return the initial state.

* Do not reference these action types directly in your code.

*

* 这些都是redux本身预置的私有action types

* 对于任何未知的action, 你一定要return当前的state.

* 如果当前的state是undefined, 你一定要return最初始的state.

* 一定,一定,一定不要在代码中直接引用action types .

*/

export const ActionTypes = {  //初始化action的type,没有action参数的时候用

       INIT: '@@redux/INIT'

}

/**

* Creates a Redux store that holds the state tree.

* The only way to change the data in the store is to call `dispatch()` on it.

* There should only be a single store in your app. To specify how different

* parts of the state tree respond to actions, you may combine several reducers

* into a single reducer function by using `combineReducers`.

*

* 创建一个包含state tree(状态树)的redux store.

* 唯一改变store中data(数据)的方法是调用`dispatch()`方法.

* 在你的程序中应该只存在唯一一个store, 来表明state tree各部分怎样对action做出反应

* 你可能需要将多个reducer用`combineReducers`组合在一起

*

* @param {Function} reducer A function that returns the next state tree, given

* the current state tree and the action to handle.

*

* @param {Function} reducer 参数reducer是一个返回下一个state tree(状态树)的函数,来操作当前的state和action

*

* @param {any} [preloadedState] The initial state. You may optionally specify it

* to hydrate the state from the server in universal apps, or to restore a

* previously serialized user session.

* If you use `combineReducers` to produce the root reducer function, this must be

* an object with the same shape as `combineReducers` keys.

*

* @param {any} [preloadedState] 初始化的state,可选参数,你可以在universal(一般的,普遍的,我不知道怎么说比较合适)

* 的程序中与服务器的state结合,或者restore一个预先连续的user session(直译过来的,一般用不到)

* 如果你用`combineReducers`产生一个根reducer函数,这一定是一个和`combineReducers`的key一样的对象(根reducer是一个对象)

*

* @param {Function} [enhancer] The store enhancer. You may optionally specify it

* to enhance the store with third-party capabilities such as middleware,

* time travel, persistence, etc. The only store enhancer that ships with Redux

* is `applyMiddleware()`.

*

* @param {Function} [enhancer] store增强器. 可选参数.用来增强第三方库的能力集(这个词是直译),

* 比如中间件,时空穿越,和持续性(也是直译).redux的store增强器是`applyMiddleware()`

*

* @returns {Store} A Redux store that lets you read the state, dispatch actions

* and subscribe to changes.

*

* @returns {Store} 返回值 一个redux的store,让你可以读取state, dispatch actions 和订阅更改

*/

//createStore的目的只是创建一个store,这个store包含5个方法(一般只用到3个,最常用的是dispatch)

export default function createStore(reducer, 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是函数的时候返回,然后执行,并将createStore作为参数传入,然后createStore就在         //enhancer里面去执行了

    return enhancer(createStore)(reducer, preloadedState)

  }

  if (typeof reducer !== 'function') {

    throw new Error('Expected the reducer to be a function.')

  }

  let currentReducer = reducer  //一般此reducer不是单个的reducer函数,而是combineReducers函数

  let currentState = preloadedState

  let currentListeners = []  //监听函数

  let nextListeners = currentListeners

  let isDispatching = false

  function ensureCanMutateNextListeners() { //nextListeners不是currentListeners

    if (nextListeners === currentListeners) {

      nextListeners = currentListeners.slice()

    }

  }

  /**

  * Reads the state tree managed by the store.

  *

  * 读取被store管理的state树

  *

  * @returns {any} The current state tree of your application.

  *

  *返回你的程序的当前的state树

  */

  function getState() {

       return currentState

  }

  /**

  * Adds a change listener. It will be called any time an action is dispatched,

  * and some part of the state tree may potentially have changed. You may then

  * call `getState()` to read the current state tree inside the callback.

  *

  * 添加一个改变事件,任何时候一个action被dispatch这个事件就会被调用,然后state树的某一部分就

  * 会改变. 你也可以在回调函数里面调用`getState()`来查看当前的state树

  *

  * You may call `dispatch()` from a change listener, with the following

  * caveats:

  *

  * 以下几种情况你也可以调用`dispatch()`

  *

  * 1. The subscriptions are snapshotted just before every `dispatch()` call.

  * If you subscribe or unsubscribe while the listeners are being invoked, this

  * will not have any effect on the `dispatch()` that is currently in progress.

  * However, the next `dispatch()` call, whether nested or not, will use a more

  * recent snapshot of the subscription list.

  *

  * 每次调用`dispatch`之前,订阅都会被snapshot,

  * 当事件被触发的时候你订阅或者不订阅,在当前的进程中都不会对`dispatch`有什么影响

  * 然而当下一次`dispatch`被调用时,无论嵌套与否,将会使用最近的订阅列表的snapshot

  *

  * 2. The listener should not expect to see all state changes, as the state

  * might have been updated multiple times during a nested `dispatch()` before

  * the listener is called. It is, however, guaranteed that all subscribers

  * registered before the `dispatch()` started will be called with the latest

  * state by the time it exits.

  *

  * 不要期待监听事件可以看到所有的状态改变,因为在事件被调用前,state在嵌套的`dispatch`间

  * 可能已经更新了很多次

  *

  * @param {Function} listener A callback to be invoked on every dispatch.

  * 每次dispatch都会被出发的回调函数

  *

  * @returns {Function} A function to remove this change listener.

  * 返回一个移除该事件的函数

  */

  function subscribe(listener) {

       if (typeof listener !== 'function') {

              throw new Error('Expected listener to be a function.')

        }

        let isSubscribed = true

        ensureCanMutateNextListeners()

         nextListeners.push(listener) //添加事件到nextListeners数组

         return function unsubscribe() {

                if (!isSubscribed) {

                        return

                 }

           isSubscribed = false

            ensureCanMutateNextListeners()

            const index = nextListeners.indexOf(listener)

             nextListeners.splice(index, 1) //从nextListeners数组中移除事件

         }

       }

  /**

  * Dispatches an action. It is the only way to trigger a state change.

  *

  * dispatch  action是唯一触发state改变的途径

  *

  * The `reducer` function, used to create the store, will be called with the

  * current state tree and the given `action`. Its return value will

  * be considered the **next** state of the tree, and the change listeners

  * will be notified.

  *

  * `reducer`函数,被用来创建store,有当前的state树和action就会被调用(state和action是reducer函数的参数)

  * 它的返回值会被当做下一个state树.监听事件会注意到state树的改变

  *

  * The base implementation only supports plain object actions. If you want to

  * dispatch a Promise, an Observable, a thunk, or something else, you need to

  * wrap your store creating function into the corresponding middleware. For

  * example, see the documentation for the `redux-thunk` package. Even the

  * middleware will eventually dispatch plain object actions using this method.

  *

  * 最基本的用法是仅支持 为纯对象的 action,如果你想要dispatch一个promise,一个Observable,

  * thunk,或是其他东西,你需要封装store创建一个进入到相应中间件的函数.  比如,看一个`redux-thunk`

  * 的文档,即使是中间件最终也会用这个方法dispatch  纯对象的action

  *

  * @param {Object} action A plain object representing “what changed”. It is

  * a good idea to keep actions serializable so you can record and replay user

  * sessions, or use the time travelling `redux-devtools`. An action must have

  * a `type` property which may not be `undefined`. It is a good idea to use

  * string constants for action types.

  *

  * action是一个纯对象,代表'什么被改变了'. 保持action的连续性是个好主意,这样你就可以记录和

  * 重现user session,或者使用时空穿梭`redux-devtools`.

  * action必须包含一个`type`属性,即使是`undefined`. 通常使用字符串常量表示

  *

  * @returns {Object} For convenience, the same action object you dispatched.

  *

  * 为了方便,返回你dispatch的action

  *

  * Note that, if you use a custom middleware, it may wrap `dispatch()` to

  * return something else (for example, a Promise you can await).

  * 注意 如果你想使用特定的中间件,可封装`dispatch`返回其他东西(比如, 一个异步调用的promise)

  *

  */

  function dispatch(action) {

    if (!isPlainObject(action)) {

      throw new Error(

        'Actions must be plain objects. ' +

        'Use custom middleware for async actions.'

      )   //actions必须为纯对象,使用特定中间件异步调用actions

    }

    if (typeof action.type === 'undefined') {

      throw new Error(

        'Actions may not have an undefined "type" property. ' +

        'Have you misspelled a constant?'

      )  //actions可能有一个未定义的type属性,你可能拼错了这个常量

    }

    if (isDispatching) {

      throw new Error('Reducers may not dispatch actions.')//reducer没有dispatch action

    }

    try {

      isDispatching = true

      //dispatch的目的就是改变currentState

      currentState = currentReducer(currentState, action) //currentReducer = reducer

    } finally {

      isDispatching = false

    }

    const listeners = currentListeners = nextListeners  //订阅函数的事件

    for (let i = 0; i < listeners.length; i++) {

      const listener = listeners[i]

      listener()

    }

    return action

  }

  /**

  * Replaces the reducer currently used by the store to calculate the state.

  *

  * 替换 store 当前用来计算 state 的 reducer。

  *

  * You might need this if your app implements code splitting and you want to

  * load some of the reducers dynamically. You might also need this if you

  * implement a hot reloading mechanism for Redux.

  *

  * 这是一个高级 API。只有在你需要实现代码分隔,而且需要立即加载一些 reducer 的时候才可能会用到它。

  *在实现 Redux 热加载机制的时候也可能会用到

  *

  * @param {Function} nextReducer The reducer for the store to use instead.

  * store所替换的reducer

  * @returns {void}

  */

  function replaceReducer(nextReducer) {

    if (typeof nextReducer !== 'function') {

      throw new Error('Expected the nextReducer to be a function.')

    }

    currentReducer = nextReducer

    dispatch({ type: ActionTypes.INIT })

  }

  /**

  * Interoperability point for observable/reactive libraries.

  * @returns {observable} A minimal observable of state changes.

  * For more information, see the observable proposal:

  * https://github.com/tc39/proposal-observable

  *

  * observable/reactive库的互用性

  * observable是一个mini的 可观察state的改变

  * 在下面这个网址查看更多observable的信息

  */

  function observable() {

    const outerSubscribe = subscribe

    return {

      /**

      * The minimal observable subscription method.

      * @param {Object} observer Any object that can be used as an observer.

      * The observer object should have a `next` method.

      * @returns {subscription} An object with an `unsubscribe` method that can

      * be used to unsubscribe the observable from the store, and prevent further

      * emission of values from the observable.

      *

      * mini的可观察订阅的方法

      * observer是 任何对象都可以用作观察者,这个观察者应该有一个`next`方法

      * subscription 一个有`unsubscribe`方法的对象.可以用做退订observable,防止进一步发出value值

      * (我也不知道什么意思,外国人说话比较随意)

      */

      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

      }

    }

  }

  // When a store is created, an "INIT" action is dispatched so that every

  // reducer returns their initial state. This effectively populates

  // the initial state tree.

  /**

  * 当创建一个store的时候,一个初始的action就被dispatch了,所以每个reducer都会返回初始的state

  * 这个可以很高效的得到state树

  */

  dispatch({ type: ActionTypes.INIT })

  return {

    dispatch,

    subscribe,

    getState,

    replaceReducer,

    [$$observable]: observable

  }

}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,658评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,482评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,213评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,395评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,487评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,523评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,525评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,300评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,753评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,048评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,223评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,905评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,541评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,168评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,417评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,094评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,088评论 2 352

推荐阅读更多精彩内容