大佬教程收集整理的这篇文章主要介绍了Redux源码学习笔记,大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。
https://github.com/reduxjs/redux 版本 4.0.0
<span style="color: #008000;">//
<span style="color: #008000;"> store 是保存数据的地方<span style="color: #008000;">//
<span style="color: #008000;"> 创建 store<span style="color: #008000;">//<span style="color: #008000;"> state 是某一时刻 store 的快照,一个 state 对应一个 view<span style="color: #008000;">
//<span style="color: #008000;"> 可通过 getState() 获取
const state =<span style="color: #000000;"> store.getState()
<span style="color: #008000;">//<span style="color: #008000;"> Action 是一个对象 用来表示 view 发出的改变 state 的通知<span style="color: #008000;">
//<span style="color: #008000;"> type 是必须的 其他属性可以自由设置
const action =<span style="color: #000000;"> {
type: 'ADD_TODO'<span style="color: #000000;">,payload: 'Learn Redux'<span style="color: #000000;">
}
<span style="color: #008000;">//<span style="color: #008000;"> 同一种类型的 action 可以写一个函数生成
const ADD_TODO = '添加 TODO'
<span style="color: #008000;">//<span style="color: #008000;"> 生成 action 的函数: Action Creator
<span style="color: #0000ff;">function<span style="color: #000000;"> addTodo(text) {
<span style="color: #0000ff;">return<span style="color: #000000;"> {
type: ADD_TODO,text
}
}
const action = addTodo('Learn Redux'<span style="color: #000000;">)
<span style="color: #008000;">//<span style="color: #008000;"> store.dispatch()是 View 发出 Action 的唯一方法。
<span style="color: #000000;">store.dispatch(action)
<span style="color: #008000;">//<span style="color: #008000;"> reducer 是 store 接收 state 返回新的 state 的过程
<span style="color: #000000;">
const defaultState = 0
<span style="color: #008000;">//<span style="color: #008000;"> reducer 接收 action 返回新的 state
const reducer = (state = defaultState,action) =><span style="color: #000000;"> {
<span style="color: #0000ff;">switch<span style="color: #000000;">(action.type) {
<span style="color: #0000ff;">case: 'ADD'<span style="color: #000000;">:
<span style="color: #0000ff;">return state +<span style="color: #000000;"> action.payload
<span style="color: #0000ff;">default<span style="color: #000000;">:
<span style="color: #0000ff;">return<span style="color: #000000;"> state
}
}
const state = reducer(1<span style="color: #000000;">,{
type: 'ADD'<span style="color: #000000;">,payload: 2<span style="color: #000000;">
})
<span style="color: #008000;">//<span style="color: #008000;"> 创建 store 时传入 reducer 当调用 store.dispatch 时将自动调用 reducer
const store =<span style="color: #000000;"> createStore(reducer)
<span style="color: #008000;">/*<span style="color: #008000;">
reducer 是一个纯函数,纯函数要求:
<span style="color: #008000;">//<span style="color: #008000;"> store.subscribe方法设置监听函数,一旦 State 发生变化,就自动执行这个函数<span style="color: #008000;">
//<span style="color: #008000;"> 返回解除监听函数
let unsubscribe = store.subsribe(() =><span style="color: #000000;"> { console.log(store.getState) })
unsubscribe() <span style="color: #008000;">//<span style="color: #008000;"> 解除监听
<span style="color: #008000;">/*<span style="color: #008000;">
store 提供的三个方法
<span style="color: #008000;">//<span style="color: #008000;"> createStore方法还可以接受第二个参数,表示 State 的最初状态。这通常是服务器给出的。<span style="color: #008000;">
//<span style="color: #008000;"> !这个初始值会覆盖 Reducer 函数默认的初始值
let store =<span style="color: #000000;"> createStore(todoApp,STATE_FROM_SERVER)
<span style="color: #008000;">//<span style="color: #008000;"> createStore 的简单实现
const createStore = (reducer) =><span style="color: #000000;"> {
let state
let listeners =<span style="color: #000000;"> []
const getState </span>= () =><span style="color: #000000;"> state
const dispatch </span>= action =><span style="color: #000000;"> {
state </span>=<span style="color: #000000;"> reducer(state,action)
listeners.forEach(listener </span>=><span style="color: #000000;"> listener())
}
const subscribe </span>= listener =><span style="color: #000000;"> {
listeners.push(listener)
</span><span style="color: #0000ff;">return</span> () =><span style="color: #000000;"> {
listeners </span>= listeners.filter(l => l !==<span style="color: #000000;"> listener)
}
}
dispatch({})
</span><span style="color: #0000ff;">return</span><span style="color: #000000;"> { getState,dispatch,subscribe }
}
<span style="color: #008000;">//<span style="color: #008000;"> 可以通过 combineReducers 来将多个 Reducer 合为一个
import { combineReducers } from 'redux'<span style="color: #000000;">
const chatReducer =<span style="color: #000000;"> combineReducers({
chatLog,statusMessage,userName
})
<span style="color: #008000;">//<span style="color: #008000;"> combineReducer 的简单实现
const combineReducers = reducers =><span style="color: #000000;"> {
<span style="color: #0000ff;">return (state = {},action) =><span style="color: #000000;">
Object.keys(reducers).reduce(
(nextState,key) =><span style="color: #000000;"> {
nextState[key] =<span style="color: #000000;"> reducerskey
<span style="color: #0000ff;">return<span style="color: #000000;"> nextState
},{}
)
}
工作流程
dispatch(action) (previousState,action)
Action Creators
======> Store ======><span style="color: #000000;"> ReducersOK 可以开始看源码了~ 网上Redux源码分析的博客真的非常多.. 不过当你知道他的源码究竟有多短 就能理解了hhh
combineReducers.js
代码一共179行 多是错误处理 我先将错误处理全部删掉 便只剩28行.....
思路就是创建一个对象 将 Reducer 全部放进去
当Action传进来的时候 就让每一个Reducer去处理这个action
每个Reducer都有一个对应的key 只处理state中对应字段 state[key] 没有Reducer对应的字段会被忽略
截取出核心代码 + 用法、感觉并不需要注释、逻辑都很直接
</span><span style="color: #0000ff;">if</span> (<span style="color: #0000ff;">typeof</span> reducers[key] === 'function'<span style="color: #000000;">) {
finalReducers[key] </span>=<span style="color: #000000;"> reducers[key]
}
}
const finalReducerKeys
nextState[key] </span>=<span style="color: #000000;"> nextStateForKey
hasChanged </span>= hasChanged || nextStateForKey !==<span style="color: #000000;"> previousStateForKey
}
</span><span style="color: #008000;">//</span><span style="color: #008000;"> 如果state每一个key都没有被修改 就直接返回原state</span>
<span style="color: #0000ff;">return</span> hasChanged ?<span style="color: #000000;"> nextState : state
}
}
<span style="color: #008000;">/*<span style="color: #008000;">**** 下面是简单的用法实例 ****<span style="color: #008000;">*/
<span style="color: #0000ff;">function todos(state =<span style="color: #000000;"> [],action) {
<span style="color: #0000ff;">switch<span style="color: #000000;"> (action.typE) {
<span style="color: #0000ff;">case 'ADD_TODO'<span style="color: #000000;">:
<span style="color: #0000ff;">return<span style="color: #000000;"> state.concat(action.text)
<span style="color: #0000ff;">default<span style="color: #000000;">:
<span style="color: #0000ff;">return<span style="color: #000000;"> state
}
}
<span style="color: #0000ff;">function counter(state = 0<span style="color: #000000;">,action) {
<span style="color: #0000ff;">switch<span style="color: #000000;"> (action.typE) {
<span style="color: #0000ff;">case 'INCREMENT'<span style="color: #000000;">:
<span style="color: #0000ff;">return state + 1
<span style="color: #0000ff;">case 'DECREMENT'<span style="color: #000000;">:
<span style="color: #0000ff;">return state - 1
<span style="color: #0000ff;">default<span style="color: #000000;">:
<span style="color: #0000ff;">return<span style="color: #000000;"> state
}
}
let reducer =<span style="color: #000000;"> combineReducers({ list: todos,number: counter })
let state = { list: [],number: 0,otherKey: 'no reducer match will be ignore'<span style="color: #000000;"> }
console.log(statE) <span style="color: #008000;">//<span style="color: #008000;"> { list: [],otherKey: 'no reducer match will be ignore' }
state = reducer(state,{ type: 'ADD_TODO',text: 'study'<span style="color: #000000;"> })
console.log(statE) <span style="color: #008000;">//<span style="color: #008000;"> { list: [ 'study' ],number: 0 }
state = reducer(state,text: 'sleep'<span style="color: #000000;"> })
console.log(statE) <span style="color: #008000;">//<span style="color: #008000;"> { list: [ 'study','sleep' ],{ type: 'INCREMENT'<span style="color: #000000;"> })
console.log(statE) <span style="color: #008000;">//<span style="color: #008000;"> { list: [ 'study',number: 1 }
s.js 源码
<span style="color: #0000ff;">function
<span style="color: #000000;"> getUndefinedStateErrormessage(key,action) {action "${String(actionTypE)}"
) || 'an action'
<span style="color: #0000ff;">return<span style="color: #000000;"> (
Given ${actionDescription},reducer </span>"${key}" returned undefined.
+<span style="color: #000000;">
To ignore an action,you must explicitly </span><span style="color: #0000ff;">return</span> the previous state.
+<span style="color: #000000;">
If you want </span><span style="color: #0000ff;">this</span> reducer to hold no value,you can <span style="color: #0000ff;">return</span> <span style="color: #0000ff;">null</span><span style="color: #000000;"> instead of undefined.
)
}
<span style="color: #0000ff;">function<span style="color: #000000;"> getUnexpectedStateShapeWarningmessage(
inputState,reducers,action,unexpectedKeyCache
) {
const reducerKeys =<span style="color: #000000;"> Object.keys(reducers)
const argumentName =<span style="color: #000000;">
action && action.type ===<span style="color: #000000;"> ActionTypes.INIT
? 'preloadedState argument passed to createStore'<span style="color: #000000;">
: 'previous state received by the reducer'
<span style="color: #0000ff;">if (reducerKeys.length === 0<span style="color: #000000;">) {
<span style="color: #0000ff;">return<span style="color: #000000;"> (
'Store does not have a valid reducer. Make sure the argument passed ' +
'to combineReducers is an object whose values are reducers.'<span style="color: #000000;">
)
}
<span style="color: #0000ff;">if (!<span style="color: #000000;">isPlainObject(inputStatE)) {
<span style="color: #008000;">//<span style="color: #008000;"> 希望 inputState 是一个简单对象:通过 new Object() 、 {} 创建 (Object.create(null) 这里好像是不合法的
<span style="color: #008000;">//<span style="color: #008000;"> [object Array] 中提取 'Array'
<span style="color: #008000;">//<span style="color: #008000;"> Object.prototype.toString.call(inputStatE).match(/\s([a-z|A-Z]+)/)[1]
<span style="color: #0000ff;">return<span style="color: #000000;"> (
The ${argumentNamE} has unexpected type of </span>"<span style="color: #000000;">
+
{}.toString.call(inputStatE).match(/\s([a-z|A-Z]+)/)[1] +
</span>". Expected argument to be an object <span style="color: #0000ff;">with</span> the following
+<span style="color: #000000;">
keys: </span>"${reducerKeys.join('","')}"<span style="color: #000000;">
)
}
<span style="color: #008000;">//<span style="color: #008000;"> 检查所有Reducer都没有处理到的key ( 此处实在不解 unexpectedKeyCache 到底何用= =
const unexpectedKeys =<span style="color: #000000;"> Object.keys(inputStatE).filter(
key => !reducers.hasOwnProperty(key) && !<span style="color: #000000;">unexpectedKeyCache[key]
)
unexpectedKeys.forEach(key =><span style="color: #000000;"> {
unexpectedKeyCache[key] = <span style="color: #0000ff;">true<span style="color: #000000;">
})
<span style="color: #008000;">//<span style="color: #008000;"> 替换 store 的 Reducer 时会调用 dispatch({ type: ActionTypes.replaCE })
<span style="color: #0000ff;">if (action && action.type === ActionTypes.replaCE) <span style="color: #0000ff;">return
<span style="color: #0000ff;">if (unexpectedKeys.length > 0<span style="color: #000000;">) {
<span style="color: #0000ff;">return<span style="color: #000000;"> (
Unexpected ${unexpectedKeys.length </span>> 1 ? 'keys' : 'key'}
+<span style="color: #000000;">
</span>"${unexpectedKeys.join('","')}" found <span style="color: #0000ff;">in</span> ${argumentNamE}.
+<span style="color: #000000;">
Expected to find one of the known reducer keys instead:
+<span style="color: #000000;">
</span>"${reducerKeys.join('","')}"<span style="color: #000000;">. Unexpected keys will be ignored.
)
}
}
<span style="color: #0000ff;">function<span style="color: #000000;"> assertReducerShape(reducers) {
Object.keys(reducers).forEach(key =><span style="color: #000000;"> {
const reducer =<span style="color: #000000;"> reducers[key]
const initialState =<span style="color: #000000;"> reducer(undefined,{ type: ActionTypes.INIT })
<span style="color: #008000;">//<span style="color: #008000;"> Reducer"$ {key}"在初始化时返回undefined。如果传递给reducer的状态未定义,你必须明确返回初始状态。
<span style="color: #008000;">//<span style="color: #008000;"> 初始状态可以是不可定义。如果你不想为这个reducer设置一个值,你可以使用Null而不是undefined。
<span style="color: #0000ff;">if (<span style="color: #0000ff;">typeof initialState === 'undefined'<span style="color: #000000;">) {
<span style="color: #0000ff;">throw <span style="color: #0000ff;">new<span style="color: #000000;"> Error(
Reducer </span>"${key}" returned undefined during initialization.
+<span style="color: #000000;">
If the state passed to the reducer is undefined,you must
+<span style="color: #000000;">
explicitly </span><span style="color: #0000ff;">return</span> the initial state. The initial state may
+<span style="color: #000000;">
not be undefined. If you don</span>'<span style="color: #000000;">t want to set a value for this reducer,
+
you can use null instead of undefined.
)
}
if (
typeof reducer(undefined,{
type: ActionTypes.PROBE_UNKNOWN_ACTION()
}) === </span>'undefined'<span style="color: #000000;">
) {
// 当使用随机类型探测Reducer${key}时返回undefined。
// 不要试图处理${ActionTypes.INIT}或者其他在"redux/*"命名空间的动作。它们被认为是私有的。
// 相反,当你遇到任何未知动作时,你必须返回当前的state,除非当前state是undefined,
// 那样你要返回初始状态,而不管动作类型。初始状态不可以是undefined,但可以为null
throw new Error(
`Reducer "${key}" returned undefined when probed with a random type. ` +
`Don</span>'t <span style="color: #0000ff;">try</span><span style="color: #000000;"> to handle ${
ActionTypes.INIT
} or other actions </span><span style="color: #0000ff;">in</span> "redux/*" ` +<span style="color: #000000;">
`namespace. They are considered private. Instead,you must </span><span style="color: #0000ff;">return</span> the ` +<span style="color: #000000;">
`current state </span><span style="color: #0000ff;">for</span> any unknown actions,unless it is undefined,` +<span style="color: #000000;">
`</span><span style="color: #0000ff;">in</span> which <span style="color: #0000ff;">case</span> you must <span style="color: #0000ff;">return</span> the initial state,regardless of the ` +<span style="color: #000000;">
`action type. The initial state may not be undefined,but can be </span><span style="color: #0000ff;">null</span><span style="color: #000000;">.`
)
}
})
}
<span style="color: #008000;">/<span style="color: #008000;">
Turns an object whose values are different reducer functions,into a single
reducer function. It will call every child reducer,and gather their results
into a single state object,whose keys correspond to the keys of the passed
reducer functions.
@param {Object} reducers An object whose values correspond to different
reducer functions that need to be combined into one. One hAndy way to obtain
it is to use ES6 import * as reducers
syntax. The reducers may never return
undefined for any action. Instead,they should return their initial state
if the state passed to them was undefined,and the current state for any
unrecognized action.
@returns {Function} A reducer function that invokes every reducer inside the
passed object,and builds a state object with the same shape.
<span style="color: #008000;">*/<span style="color: #000000;">
export <span style="color: #0000ff;">default <span style="color: #0000ff;">function<span style="color: #000000;"> combineReducers(reducers) {
const reducerKeys =<span style="color: #000000;"> Object.keys(reducers)
const finalReducers =<span style="color: #000000;"> {}
<span style="color: #0000ff;">for (let i = 0; i < reducerKeys.length; i++<span style="color: #000000;">) {
const key =<span style="color: #000000;"> reducerKeys[i]
<span style="color: #0000ff;">if (process.env.NODE_ENV !== 'production'<span style="color: #000000;">) {
<span style="color: #0000ff;">if (<span style="color: #0000ff;">typeof reducers[key] === 'undefined'<span style="color: #000000;">) {
warning(No reducer provided </span><span style="color: #0000ff;">for</span> key "${key}"<span style="color: #000000;">
)
}
}
<span style="color: #0000ff;">if (<span style="color: #0000ff;">typeof reducers[key] === 'function'<span style="color: #000000;">) {
finalReducers[key] =<span style="color: #000000;"> reducers[key]
}
}
const finalReducerKeys =<span style="color: #000000;"> Object.keys(finalReducers)
let unexpectedKeyCache
<span style="color: #0000ff;">if (process.env.NODE_ENV !== 'production'<span style="color: #000000;">) {
unexpectedKeyCache =<span style="color: #000000;"> {}
}
let shapeAssertionError
<span style="color: #0000ff;">try<span style="color: #000000;"> {
<span style="color: #008000;">//<span style="color: #008000;"> 判断每个reducer都有初始值和对于未知action返回原state
<span style="color: #000000;"> assertReducerShape(finalReducers)
} <span style="color: #0000ff;">catch<span style="color: #000000;"> (E) {
shapeAssertionError =<span style="color: #000000;"> e
}
<span style="color: #0000ff;">return <span style="color: #0000ff;">function combination(state =<span style="color: #000000;"> {},action) {
<span style="color: #0000ff;">if<span style="color: #000000;"> (shapeAssertionError) {
<span style="color: #0000ff;">throw<span style="color: #000000;"> shapeAssertionError
}
</span><span style="color: #0000ff;">if</span> (process.env.NODE_ENV !== 'production'<span style="color: #000000;">) {
const warningmessage </span>=<span style="color: #000000;"> getUnexpectedStateShapeWarningmessage(
state,finalReducers,unexpectedKeyCache
)
</span><span style="color: #0000ff;">if</span><span style="color: #000000;"> (warningmessagE) {
warning(warningmessagE)
}
}
let hasChanged </span>= <span style="color: #0000ff;">false</span><span style="color: #000000;">
const nextState </span>=<span style="color: #000000;"> {}
</span><span style="color: #0000ff;">for</span> (let i = 0; i < finalReducerKeys.length; i++<span style="color: #000000;">) {
const key </span>=<span style="color: #000000;"> finalReducerKeys[i]
const reducer </span>=<span style="color: #000000;"> finalReducers[key]
const previousStateForKey </span>=<span style="color: #000000;"> state[key]
const nextStateForKey </span>=<span style="color: #000000;"> reducer(previousStateForKey,action)
</span><span style="color: #0000ff;">if</span> (<span style="color: #0000ff;">typeof</span> nextStateForKey === 'undefined'<span style="color: #000000;">) {
const errormessage </span>=<span style="color: #000000;"> getUndefinedStateErrormessage(key,action)
</span><span style="color: #0000ff;">throw</span> <span style="color: #0000ff;">new</span><span style="color: #000000;"> Error(errormessagE)
}
nextState[key] </span>=<span style="color: #000000;"> nextStateForKey
hasChanged </span>= hasChanged || nextStateForKey !==<span style="color: #000000;"> previousStateForKey
}
</span><span style="color: #008000;">//</span><span style="color: #008000;"> 如果state每一个key都没有被修改 就直接返回原state</span>
<span style="color: #0000ff;">return</span> hasChanged ?<span style="color: #000000;"> nextState : state
}
}
s.js
是redux核心代码,不过这个没有什么难理解的地方
<span style="color: #008000;">//<span style="color: #008000;"> 创建 store 的函数<span style="color: #008000;">
//<span style="color: #008000;"> preloadedState: store设置的初始值 这个值会覆盖 Reducer 的默认值<span style="color: #008000;">
//<span style="color: #008000;"> 如果使用了 combineReducers preloadedState 要和 combineReducers 有相同的keys<span style="color: #008000;">
//<span style="color: #008000;"> enhancer: 中间件
export <span style="color: #0000ff;">default <span style="color: #0000ff;">function<span style="color: #000000;"> createStore(reducer,preloadedState,enhancer) {
<span style="color: #008000;">//<span style="color: #008000;"> preloadedState可以不传 判断preloadedState是否存在
<span style="color: #0000ff;">if (<span style="color: #0000ff;">typeof preloadedState === 'function' && <span style="color: #0000ff;">typeof enhancer === 'undefined'<span style="color: #000000;">) {
enhancer =<span style="color: #000000;"> preloadedState
preloadedState =<span style="color: #000000;"> undefined
}
<span style="color: #0000ff;">if (<span style="color: #0000ff;">typeof enhancer !== 'undefined'<span style="color: #000000;">) {
<span style="color: #0000ff;">if (<span style="color: #0000ff;">typeof enhancer !== 'function'<span style="color: #000000;">) {
<span style="color: #0000ff;">throw <span style="color: #0000ff;">new Error('Expected the enhancer to be a function.'<span style="color: #000000;">)
}
<span style="color: #008000;">//<span style="color: #008000;"> enhancer是一个高阶函数 调用enhancer返回一个"加强版"的createStore
<span style="color: #0000ff;">return<span style="color: #000000;"> enhancer(createStorE)(reducer,preloadedStatE)
}
<span style="color: #0000ff;">if (<span style="color: #0000ff;">typeof reducer !== 'function'<span style="color: #000000;">) {
<span style="color: #0000ff;">throw <span style="color: #0000ff;">new Error('Expected the reducer to be a function.'<span style="color: #000000;">)
}
let currentReducer =<span style="color: #000000;"> reducer
let currentState =<span style="color: #000000;"> preloadedState
let currentListeners =<span style="color: #000000;"> []
let nextListeners =<span style="color: #000000;"> currentListeners
let isDispatching = <span style="color: #0000ff;">false
<span style="color: #008000;">//<span style="color: #008000;"> 判断当前 nextListeners 和 currentListeners 是否为同一个对象
<span style="color: #008000;">//<span style="color: #008000;"> 如果是一个对象 就把 nextListeners 改为 currentListeners 的副本
<span style="color: #0000ff;">function<span style="color: #000000;"> ensureCanMutateNextListeners() {
<span style="color: #0000ff;">if (nextListeners ===<span style="color: #000000;"> currentListeners) {
nextListeners =<span style="color: #000000;"> currentListeners.slice()
}
}
<span style="color: #008000;">//<span style="color: #008000;"> 获取当前对象 如果是正在派发action 则不能获取state
<span style="color: #0000ff;">function<span style="color: #000000;"> getState() {
<span style="color: #0000ff;">if<span style="color: #000000;"> (isDispatching) {
<span style="color: #0000ff;">throw <span style="color: #0000ff;">new<span style="color: #000000;"> Error(
'You may not call store.getState() while the reducer is execuTing. ' +
'The reducer has already received the state as an argument. ' +
'Pass it down from the top reducer instead of reading it from the store.'<span style="color: #000000;">
)
}
</span><span style="color: #0000ff;">return</span><span style="color: #000000;"> currentState
}
<span style="color: #008000;">//<span style="color: #008000;"> 订阅 添加订阅者
<span style="color: #0000ff;">function<span style="color: #000000;"> subscribe(listener) {
<span style="color: #0000ff;">if (<span style="color: #0000ff;">typeof listener !== 'function'<span style="color: #000000;">) {
<span style="color: #0000ff;">throw <span style="color: #0000ff;">new Error('Expected the listener to be a function.'<span style="color: #000000;">)
}
</span><span style="color: #0000ff;">if</span><span style="color: #000000;"> (isDispatching) {
</span><span style="color: #0000ff;">throw</span> <span style="color: #0000ff;">new</span><span style="color: #000000;"> Error(
</span>'You may not call store.subscribe() while the reducer is execuTing. ' +
'If you would like to be notified after the store has been updated,subscribe from a ' +
'component and invoke store.getState() in the callBACk to access the latest state. ' +
'See https://redux.js.org/api-reference/store#subscribe(listener) for more details.'<span style="color: #000000;">
)
}
let isSubscribed </span>= <span style="color: #0000ff;">true</span>
<span style="color: #008000;">//</span><span style="color: #008000;"> 每次修改 nextListeners 都要判断一下 nextListeners 和 currentListeners 是否为同一个对象</span>
<span style="color: #000000;"> ensureCanMutateNextListeners()
<span style="color: #008000;">//<span style="color: #008000;"> 注意 这里修改 nextListeners 之后并没有改变 currentListeners 而是在下一次用到 currentListeners 才会改变
<span style="color: #000000;"> nextListeners.push(listener)
</span><span style="color: #008000;">//</span><span style="color: #008000;"> 返回一个当前监听者取消订阅的方法</span>
<span style="color: #0000ff;">return</span> <span style="color: #0000ff;">function</span><span style="color: #000000;"> unsubscribe() {
</span><span style="color: #0000ff;">if</span> (!<span style="color: #000000;">isSubscribed) {
</span><span style="color: #0000ff;">return</span><span style="color: #000000;">
}
</span><span style="color: #008000;">//</span><span style="color: #008000;"> 正在派发 action 时不能进行操作</span>
<span style="color: #0000ff;">if</span><span style="color: #000000;"> (isDispatching) {
</span><span style="color: #0000ff;">throw</span> <span style="color: #0000ff;">new</span><span style="color: #000000;"> Error(
</span>'You may not unsubscribe from a store listener while the reducer is execuTing. ' +
'See https://redux.js.org/api-reference/store#subscribe(listener) for more details.'<span style="color: #000000;">
)
}
isSubscribed </span>= <span style="color: #0000ff;">false</span><span style="color: #000000;">
ensureCanMutateNextListeners()
const index </span>=<span style="color: #000000;"> nextListeners.indexOf(listener)
nextListeners.splice(index,</span>1<span style="color: #000000;">)
}
}
<span style="color: #0000ff;">function<span style="color: #000000;"> dispatch(action) {
<span style="color: #0000ff;">if (!<span style="color: #000000;">isPlainObject(action)) {
<span style="color: #0000ff;">throw <span style="color: #0000ff;">new<span style="color: #000000;"> Error(
'Actions must be plain objects. ' +
'Use custom middleware for async actions.'<span style="color: #000000;">
)
}
</span><span style="color: #0000ff;">if</span> (<span style="color: #0000ff;">typeof</span> action.type === 'undefined'<span style="color: #000000;">) {
</span><span style="color: #0000ff;">throw</span> <span style="color: #0000ff;">new</span><span style="color: #000000;"> Error(
</span>'Actions may not have an undefined "type" property. ' +
'Have you misspelled a constant?'<span style="color: #000000;">
)
}
</span><span style="color: #0000ff;">if</span><span style="color: #000000;"> (isDispatching) {
</span><span style="color: #0000ff;">throw</span> <span style="color: #0000ff;">new</span> Error('Reducers may not dispatch actions.'<span style="color: #000000;">)
}
</span><span style="color: #0000ff;">try</span><span style="color: #000000;"> {
</span><span style="color: #008000;">//</span><span style="color: #008000;"> 用 isDispatching 记录是否正在 派发action 过程中不能进行其他操作</span>
isDispatching = <span style="color: #0000ff;">true</span><span style="color: #000000;">
currentState </span>=<span style="color: #000000;"> currentReducer(currentState,action)
} </span><span style="color: #0000ff;">finally</span><span style="color: #000000;"> {
isDispatching </span>= <span style="color: #0000ff;">false</span><span style="color: #000000;">
}
</span><span style="color: #008000;">//</span><span style="color: #008000;"> 用到 listeners 才会修改 currentListeners 以减少修改次数</span>
const listeners = (currentListeners =<span style="color: #000000;"> nextListeners)
</span><span style="color: #0000ff;">for</span> (let i = 0; i < listeners.length; i++<span style="color: #000000;">) {
const listener </span>=<span style="color: #000000;"> listeners[i]
listener()
}
</span><span style="color: #0000ff;">return</span><span style="color: #000000;"> action
}
<span style="color: #008000;">//<span style="color: #008000;"> 替换 Reducer 并派发动作 ActionTypes.replaCE 相当于对state重新进行初始化
<span style="color: #0000ff;">function<span style="color: #000000;"> replaceReducer(nextReducer) {
<span style="color: #0000ff;">if (<span style="color: #0000ff;">typeof nextReducer !== 'function'<span style="color: #000000;">) {
<span style="color: #0000ff;">throw <span style="color: #0000ff;">new Error('Expected the nextReducer to be a function.'<span style="color: #000000;">)
}
currentReducer </span>=<span style="color: #000000;"> nextReducer
dispatch({ type: ActionTypes.replaCE })
}
<span style="color: #008000;">//<span style="color: #008000;"> emmmm...看不懂这个 可以参考 https://distums.github.io/2017/03/19/observables-proposal-for-ecmascript/
<span style="color: #0000ff;">function<span style="color: #000000;"> observable() {
const outerSubscribe =<span style="color: #000000;"> subscribe
<span style="color: #0000ff;">return<span style="color: #000000;"> {
subscribe(observer) {
<span style="color: #0000ff;">if (<span style="color: #0000ff;">typeof observer !== 'object' || observer === <span style="color: #0000ff;">null<span style="color: #000000;">) {
<span style="color: #0000ff;">throw <span style="color: #0000ff;">new TypeError('Expected the observer to be an object.'<span style="color: #000000;">)
}
</span><span style="color: #0000ff;">function</span><span style="color: #000000;"> observeState() {
</span><span style="color: #0000ff;">if</span><span style="color: #000000;"> (observer.next) {
observer.next(getState())
}
}
observeState()
const unsubscribe </span>=<span style="color: #000000;"> outerSubscribe(observeStatE)
</span><span style="color: #0000ff;">return</span><span style="color: #000000;"> { unsubscribe }
},[$$observable]() {
</span><span style="color: #0000ff;">return</span> <span style="color: #0000ff;">this</span><span style="color: #000000;">
}
}
}
dispatch({ type: ActionTypes.INIT })
<span style="color: #0000ff;">return<span style="color: #000000;"> {
dispatch,subscribe,getState,replaceReducer,[$$observable]: observable
}
}
s.js
此处参考 《http://imweb.io/topic/5a426d32a192c3b460fce354" target="_blank">mapStateToProps,mapDispatchToProps的使用姿势》
按注释