继上一篇文章《为何 redux 要返回一个新的 state 引起的血案》以后,过了半个月我彭三汉又回来了,直接看源码,github 戳这里,咱们能够看到这样的文件架构javascript
·
├── utils
│ ├── actionTypes
│ ├── isPlainObject
│ ├── warning
│ └─
│
├── applyMiddleware
│
├── bindActionCreatorts
│
├── combineReducers
│
├── compose
│
├── createStore
│
├── index.js
│
└─
复制代码
看起来文件比较少,因此,开始跟我阿宽,不对,跟着各路大哥们的总结,一块儿看源码吧。java
从小妈妈就告诉我,看源码要从 index.js 入手,就我看来,index都做为入口文件
,因此咱们去 index.js 中看一下代码。简单明了,我就很少说~git
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'
/* * 这是一个虚函数,用于检查函数名称是否已被缩小更改. * 若是这个函数被修改且 NODE_ENV !== 'production',警告用户 */
function isCrushed() {}
if (
process.env.NODE_ENV !== 'production' &&
typeof isCrushed.name === 'string' &&
isCrushed.name !== 'isCrushed'
) {
warning('巴拉巴拉,要看提示就去看源码哈')
}
export {
createStore,
combineReducers,
bindActionCreators,
applyMiddleware,
compose,
__DO_NOT_USE__ActionTypes
}
复制代码
咱们回顾下以前说的 :redux 中最核心的 API 就是 —— createStore
, 如何使用呢 ?github
const store = createStore(reducers, preloadedState, enhance)
复制代码
三个参数,reducers、preloadedState、enhance,源码中也有对这三个参数给出了解释redux
/** * 建立一个包含状态树的Redux存储 * 更改store中数据的惟一方法是在其上调用 `dispatch()` * * 你的app中应该只有一个store,指定状态树的不一样部分如何响应操做 * 你可使用 `combineReducers` 将几个reducer组合成一个reducer函数 * * @param {Function} reducer 给定当前状态树和要处理的操做的函数,返回下一个状态树 * * @param {any} [preloadedState] 初始状态. 你能够选择将其指定为中的universal apps服务器状态,或者还原之前序列化的用户会话。 * 若是你使用 `combineReducers` 来产生 root reducer 函数,那么它必须是一个与 `combineReducers` 键形状相同的对象 * * @param {Function} [enhancer] store enhancer. 你能够选择指定它来加强store的第三方功能 * 好比 middleware、time travel、persistence, Redux附带的惟一商店加强器是 `applyMiddleware()` * * @returns {Store} Redux Store,容许您读取状态,调度操做和订阅更改。 */
复制代码
看完了上面的解释,(...谷歌翻译好累啊), 咱们继续往下看,咱们从Redux 官网中,能看到,Store Mehods 有四个方法,源码中也有看获得~api
import $$observable from 'symbol-observable'
import ActionTypes from './utils/actionTypes'
import isPlainObject from './utils/isPlainObject'
export default function createStore(reducer, preloadedState, enhancer) {
// ...
// 检查一哈你的state和enhancer参数是否传反
if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') {
enhancer = preloadedState
preloadedState = undefined
}
// 若是有传入合法的enhance,则经过enhancer再调用一次createStore
if (typeof enhancer !== 'undefined') {
// enhancer 指望获得的是一个函数
if (typeof enhancer !== 'function') {
throw new Error('Expected the enhancer to be a function.')
}
return enhancer(createStore)(reducer, preloadedState)
}
// reducer 指望获得的是一个函数
if (typeof reducer !== 'function') {
throw new Error('Expected the reducer to be a function.')
}
let currentReducer = reducer
let currentState = preloadedState
let currentListeners = []
let nextListeners = currentListeners
let isDispatching = false // 是否正在分发事件
function ensureCanMutateNextListeners() {
if (nextListeners === currentListeners) {
nextListeners = currentListeners.slice()
}
}
// 通常在action middleware 中常常会使用 `getState()`方法去获取当前的state
function getState() {
if (isDispatching) {
throw new Error(
// ...
)
}
return currentState
}
// 源码中这个函数的解释太长了,我大概读懂了,可是就不写翻译了哈,大概以下
// 注册listener,同时返回一个取消事件注册的方法。当调用store.dispatch的时候调用listener
function subscribe(listener) {
if (typeof listener !== 'function') {
throw new Error(
'期待 listener 是一个函数'
)
}
if (isDispatching) {
throw new Error(
'在reducer执行时,您可能没法调用store.subscribe(),若是你但愿在更新store后收到通知,
请从组件订阅并在回调中调用 store.getState() 以访问最新状态'
)
}
let isSubscribed = true
ensureCanMutateNextListeners()
nextListeners.push(listener)
return function unsubscribe() {
if(!isSubscribed) {
return
}
if (isDispatching) {
throw new Error(
'在reducer执行时,你可能没法取消订阅store侦听器'
)
}
isSubscribed = false
// 从 nextListeners 中去除掉当前 listener
ensureCanMutateNextListeners()
const index = nextListeners.indexOf(listener)
nextListeners.splice(index, 1)
}
}
// dispatch方法接收的action是个对象,而不是方法。dispatch()是触发状态变化的惟一方法。
// 这个对象实际上就是咱们自定义action的返回值,由于dispatch的时候,已经调用过咱们的自定义action了
// 更多详情去官网看讲解 : https://redux.js.org/api/store#example
function dispatch(action) {
if (!isPlainObject(action)) { // isPlainObject 最上边 import 进来的
throw new Error(
'Actions 必须是一个普通对象'
)
}
if (typeof action.type === 'undefined') {
throw new Error(
'Actions 可能没有未定义的“类型”属性'
)
}
// 调用dispatch的时候只能一个个调用,经过dispatch判断调用的状态
if (isDispatching) {
throw new Error(
// ...
)
}
try {
isDispatching = true
currentState = currentReducer(currentState, action)
} finally {
isDispatching = false
}
const listeners = (currentListeners = nextListeners)
// 遍历调用每一个 listener
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.
function replaceReducer(nextReducer) {
if (typeof nextReducer !== 'function') {
throw new Error(
// ...
)
}
currentReducer = nextReducer
dispatch({
type: ActionTypes.REPLACE // ActionTypes 最上边 import 进来的
})
}
// ...
// 当create store的时候,reducer会接受一个type为ActionTypes.INIT的action,使reducer返回他们默认的state,这样能够快速的造成默认的state的结构
dispatch({
type: ActionTypes.INIT
})
return {
dispatch,
subscribe,
getState,
replaceReducer,
[$$observable]: observable
}
}
复制代码
是否是不多,不少英文注释都去掉了,包括 throw new Error
我也没写出来,我更推荐的是,本身去看源码!!!bash
彩蛋嘛,就是咱们来揭开上边中提到的 actionTypes
和 isPlainObject
中的神秘面纱~服务器
actionTypes.js架构
/** * 这些是Redux保留的私有操做类型 * 对于任何未知 actions,你必须返回当前状态 * 若是当前的 state 是 undefined,你必须返回初始state * 不要直接在代码中引用这些操做类型 */
const randomString = () =>
Math.random()
.toString(36)
.substring(7)
.split('')
.join('.')
const ActionTypes = {
INIT: `@@redux/INIT${randomString()}`,
REPLACE: `@@redux/REPLACE${randomString()}`,
PROBE_UNKNOWN_ACTION: () => `@@redux/PROBE_UNKNOWN_ACTION${randomString()}`
}
export default ActionTypes
复制代码
isPlainObject.jsapp
/** * 若是参数是普通对象,则返回true * Object.getPrototypeOf() 方法返回指定对象的原型,若是没有继承属性,则返回 null */
export default function isPlainObject(obj) {
if (typeof obj !== 'object' || obj === null) return false
let proto = obj
while (Object.getPrototypeOf(proto) !== null) {
proto = Object.getPrototypeOf(proto)
}
return Object.getPrototypeOf(obj) === proto
}
复制代码
上一篇在这里 : 《为何redux要返回一个新的state引起的血案》
写博客文章实在太累了,因此还有下一集,还有上边若是有错,请大哥们指出,说真,我也是去 github 看源码,去官网看文档,搜一些大哥们的文章,还要打开谷歌翻译;
其实我写的,也都是站在各位大哥的肩膀上去结合本身理解写的总结,键盘侠就不要看了,求求大家了,大家太牛逼了,直接去看源码吧,传送门在底下~要不这也给你一个连接吧
还有关于为何只贴代码,是由于,直接看代码是最直观的!,好比一个美女,你要我告诉你,她有多么的沉鱼落雁、闭月羞花、国色天香...,仍是你直接看比较直观?
《Redux 源码》: github.com/reduxjs/red…
《Redux 官网》: redux.js.org/api/store#s…
《Object.getPrototypeOf() 》: developer.mozilla.org/en-US/docs/…