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
}
}
源码剖析请参考 https://segmentfault.com/a/11…