程序笔记   发布时间:2019-11-07  发布网站:大佬教程  code.js-code.com
大佬教程收集整理的这篇文章主要介绍了Redux源码学习笔记大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。

https://github.com/reduxjs/redux 版本 4.0.0

先了解一下redux是怎么用的,此处摘抄自阮一峰老师的《

<span style="color: #008000;">//<span style="color: #008000;"> store 是保存数据的地方

<span style="color: #008000;">//<span style="color: #008000;"> 创建 store
import { createStore } from 'redux'<span style="color: #000000;">
const store =<span style="color: #000000;"> createStore(fn)

<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 是一个纯函数,纯函数要求:

  • 不得改写参数
  • 不能调用系统 I/O 的API
  • 不能调用Date.now()或者Math.random()等不纯的方法,因为每次会得到不一样的结果
    <span style="color: #008000;">*/

<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 提供的三个方法

  • store.getState()
  • store.dispatch()
  • store.subscribe()
    <span style="color: #008000;">*/

<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;"&gt; state

const dispatch </span>= action =><span style="color: #000000;"&gt; {
    state </span>=<span style="color: #000000;"&gt; reducer(state,action)
    listeners.forEach(listener </span>=><span style="color: #000000;"&gt; listener())
}

const subscribe </span>= listener =><span style="color: #000000;"&gt; {
    listeners.push(listener)
    </span><span style="color: #0000ff;"&gt;return</span> () =><span style="color: #000000;"&gt; {
        listeners </span>= listeners.filter(l => l !==<span style="color: #000000;"&gt; listener)
    }
}

dispatch({})

</span><span style="color: #0000ff;"&gt;return</span><span style="color: #000000;"&gt; { 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;"> reducers
key
<span style="color: #0000ff;">return<span style="color: #000000;"> nextState
},{}
)
}

工作流程

dispatch(action) (previousState,action)

Action Creators ======> Store ======><span style="color: #000000;"> Reducers
^ || <======<span style="color: #000000;">
_ ||<span style="color: #000000;"> (newStatE)
_ (statE) ||<span style="color: #000000;">
_ ||<span style="color: #000000;">
(view opt)_ \/<span style="color: #000000;">
\--- React Comonents

OK 可以开始看源码了~ 网上Redux源码分析的博客真的非常多.. 不过当你知道他的源码究竟有多短 就能理解了hhh 

combineReducers.js 

代码一共179行 多是错误处理 我先将错误处理全部删掉 便只剩28行.....

思路就是创建一个对象 将 Reducer 全部放进去

当Action传进来的时候 就让每一个Reducer去处理这个action

每个Reducer都有一个对应的key 只处理state中对应字段 state[key] 没有Reducer对应的字段会被忽略

截取出核心代码 + 用法、感觉并不需要注释、逻辑都很直接

{ const reducerKeys =ject.keys(reducers) const finalReducers ={} (let i = 0; i < reducerKeys.length; i++{ const key =</span><span style="color: #0000ff;"&gt;if</span> (<span style="color: #0000ff;"&gt;typeof</span> reducers[key] === 'function'<span style="color: #000000;"&gt;) { finalReducers[key] </span>=<span style="color: #000000;"&gt; reducers[key] }

}
const finalReducerKeys =<span style="color: #000000;"> Object.keys(finalReducers)

<span style="color: #0000ff;">return <span style="color: #0000ff;">function combination(state =<span style="color: #000000;"> {},action) {
let hasChanged = <span style="color: #0000ff;">false<span style="color: #000000;">
const nextState =<span style="color: #000000;"> {}
<span style="color: #0000ff;">for (let i = 0; i < finalReducerKeys.length; i++<span style="color: #000000;">) {
const key =<span style="color: #000000;"> finalReducerKeys[i]
const reducer =<span style="color: #000000;"> finalReducers[key]
const previousStateForKey =<span style="color: #000000;"> state[key]
const nextStateForKey =<span style="color: #000000;"> reducer(previousStateForKey,action)

  nextState[key] </span>=<span style="color: #000000;"&gt; nextStateForKey
  hasChanged </span>= hasChanged || nextStateForKey !==<span style="color: #000000;"&gt; previousStateForKey
}
</span><span style="color: #008000;"&gt;//</span><span style="color: #008000;"&gt; 如果state每一个key都没有被修改 就直接返回原state</span>
<span style="color: #0000ff;"&gt;return</span> hasChanged ?<span style="color: #000000;"&gt; 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 源码

https://cn.js-code.com/res/2019/02-05/22/1c53668bcee393edac0d7b3b3daff1ae.gif" alt="">https://cn.js-code.com/res/2019/02-05/22/405b18b4b6584ae338e0f6ecaf736533.gif" alt="">
import ActionTypes from './utils/actionTypes''./utils/warning'ject from './utils/isPlainObject'

<span style="color: #0000ff;">function<span style="color: #000000;"> getUndefinedStateErrormessage(key,action) {
const actionType = action &&<span style="color: #000000;"> action.type
const actionDescription =<span style="color: #000000;">
(actionType && 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;"&gt;return</span> the previous state. +<span style="color: #000000;">
If you want </span><span style="color: #0000ff;"&gt;this</span> reducer to hold no value,you can <span style="color: #0000ff;"&gt;return</span> <span style="color: #0000ff;"&gt;null</span><span style="color: #000000;"&gt; 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;"&gt; +
{}.toString.call(inputStatE).match(/\s([a-z|A-Z]+)/)[1] +
</span>". Expected argument to be an object <span style="color: #0000ff;"&gt;with</span> the following +<span style="color: #000000;">
keys: </span>"${reducerKeys.join('","')}"<span style="color: #000000;"&gt;
)
}
<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;"&gt;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;"&gt;. 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;"&gt;return</span> the initial state. The initial state may +<span style="color: #000000;">
not be undefined. If you don</span>'<span style="color: #000000;"&gt;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;"&gt;
) {
  // 当使用随机类型探测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;"&gt;try</span><span style="color: #000000;"&gt; to handle ${
        ActionTypes.INIT
      } or other actions </span><span style="color: #0000ff;"&gt;in</span> "redux/*" ` +<span style="color: #000000;"&gt;
      `namespace. They are considered private. Instead,you must </span><span style="color: #0000ff;"&gt;return</span> the ` +<span style="color: #000000;"&gt;
      `current state </span><span style="color: #0000ff;"&gt;for</span> any unknown actions,unless it is undefined,` +<span style="color: #000000;"&gt;
      `</span><span style="color: #0000ff;"&gt;in</span> which <span style="color: #0000ff;"&gt;case</span> you must <span style="color: #0000ff;"&gt;return</span> the initial state,regardless of the ` +<span style="color: #000000;"&gt;
      `action type. The initial state may not be undefined,but can be </span><span style="color: #0000ff;"&gt;null</span><span style="color: #000000;"&gt;.`
  )
}

})
}

<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;"&gt;for</span> key "${key}"<span style="color: #000000;"&gt;)
    }
    }

    <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;"&gt;if</span> (process.env.NODE_ENV !== 'production'<span style="color: #000000;"&gt;) {
  const warningmessage </span>=<span style="color: #000000;"&gt; getUnexpectedStateShapeWarningmessage(
    state,finalReducers,unexpectedKeyCache
  )
  </span><span style="color: #0000ff;"&gt;if</span><span style="color: #000000;"&gt; (warningmessagE) {
    warning(warningmessagE)
  }
}

let hasChanged </span>= <span style="color: #0000ff;"&gt;false</span><span style="color: #000000;"&gt;
const nextState </span>=<span style="color: #000000;"&gt; {}
</span><span style="color: #0000ff;"&gt;for</span> (let i = 0; i < finalReducerKeys.length; i++<span style="color: #000000;"&gt;) {
  const key </span>=<span style="color: #000000;"&gt; finalReducerKeys[i]
  const reducer </span>=<span style="color: #000000;"&gt; finalReducers[key]
  const previousStateForKey </span>=<span style="color: #000000;"&gt; state[key]
  const nextStateForKey </span>=<span style="color: #000000;"&gt; reducer(previousStateForKey,action)
  </span><span style="color: #0000ff;"&gt;if</span> (<span style="color: #0000ff;"&gt;typeof</span> nextStateForKey === 'undefined'<span style="color: #000000;"&gt;) {
    const errormessage </span>=<span style="color: #000000;"&gt; getUndefinedStateErrormessage(key,action)
    </span><span style="color: #0000ff;"&gt;throw</span> <span style="color: #0000ff;"&gt;new</span><span style="color: #000000;"&gt; Error(errormessagE)
  }
  nextState[key] </span>=<span style="color: #000000;"&gt; nextStateForKey
  hasChanged </span>= hasChanged || nextStateForKey !==<span style="color: #000000;"&gt; previousStateForKey
}
</span><span style="color: #008000;"&gt;//</span><span style="color: #008000;"&gt; 如果state每一个key都没有被修改 就直接返回原state</span>
<span style="color: #0000ff;"&gt;return</span> hasChanged ?<span style="color: #000000;"&gt; nextState : state

}
}

s.js

可以参0-9a-z' 的随机字符串 const randomString = () =>String(36String(7'''.' const ActionTypes ={ INIT: `@@redux/INIT${randomString()}`,replaCE: `@@redux/replaCE${randomString()}`,PROBE_UNKNOWN_ACTION: () => `@@redux/PROBE_UNKNOWN_ACTION${randomString()}` export <span style="color: #0000ff;">default ActionTypes

是redux核心代码,不过这个没有什么难理解的地方

import $$observable from 'symbol-observable'import ActionTypes from './utils/actionTypes'<span style="color: #000000;">
import isPlainObject from './utils/isPlainObject'

<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;"&gt;return</span><span style="color: #000000;"&gt; 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;"&gt;if</span><span style="color: #000000;"&gt; (isDispatching) {
  </span><span style="color: #0000ff;"&gt;throw</span> <span style="color: #0000ff;"&gt;new</span><span style="color: #000000;"&gt; 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;"&gt;
  )
}

let isSubscribed </span>= <span style="color: #0000ff;"&gt;true</span>
<span style="color: #008000;"&gt;//</span><span style="color: #008000;"&gt; 每次修改 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;"&gt;//</span><span style="color: #008000;"&gt; 返回一个当前监听者取消订阅的方法</span>
<span style="color: #0000ff;"&gt;return</span> <span style="color: #0000ff;"&gt;function</span><span style="color: #000000;"&gt; unsubscribe() {
  </span><span style="color: #0000ff;"&gt;if</span> (!<span style="color: #000000;"&gt;isSubscribed) {
    </span><span style="color: #0000ff;"&gt;return</span><span style="color: #000000;"&gt;
  }
  </span><span style="color: #008000;"&gt;//</span><span style="color: #008000;"&gt; 正在派发 action 时不能进行操作</span>
  <span style="color: #0000ff;"&gt;if</span><span style="color: #000000;"&gt; (isDispatching) {
    </span><span style="color: #0000ff;"&gt;throw</span> <span style="color: #0000ff;"&gt;new</span><span style="color: #000000;"&gt; 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;"&gt;
    )
  }

  isSubscribed </span>= <span style="color: #0000ff;"&gt;false</span><span style="color: #000000;"&gt;

  ensureCanMutateNextListeners()
  const index </span>=<span style="color: #000000;"&gt; nextListeners.indexOf(listener)
  nextListeners.splice(index,</span>1<span style="color: #000000;"&gt;)
}

}

<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;"&gt;if</span> (<span style="color: #0000ff;"&gt;typeof</span> action.type === 'undefined'<span style="color: #000000;"&gt;) {
  </span><span style="color: #0000ff;"&gt;throw</span> <span style="color: #0000ff;"&gt;new</span><span style="color: #000000;"&gt; Error(
    </span>'Actions may not have an undefined "type" property. ' +
      'Have you misspelled a constant?'<span style="color: #000000;"&gt;
  )
}

</span><span style="color: #0000ff;"&gt;if</span><span style="color: #000000;"&gt; (isDispatching) {
  </span><span style="color: #0000ff;"&gt;throw</span> <span style="color: #0000ff;"&gt;new</span> Error('Reducers may not dispatch actions.'<span style="color: #000000;"&gt;)
}

</span><span style="color: #0000ff;"&gt;try</span><span style="color: #000000;"&gt; {
  </span><span style="color: #008000;"&gt;//</span><span style="color: #008000;"&gt; 用 isDispatching 记录是否正在 派发action 过程中不能进行其他操作</span>
  isDispatching = <span style="color: #0000ff;"&gt;true</span><span style="color: #000000;"&gt;
  currentState </span>=<span style="color: #000000;"&gt; currentReducer(currentState,action)
} </span><span style="color: #0000ff;"&gt;finally</span><span style="color: #000000;"&gt; {
  isDispatching </span>= <span style="color: #0000ff;"&gt;false</span><span style="color: #000000;"&gt;
}
</span><span style="color: #008000;"&gt;//</span><span style="color: #008000;"&gt; 用到 listeners 才会修改 currentListeners 以减少修改次数</span>
const listeners = (currentListeners =<span style="color: #000000;"&gt; nextListeners)
</span><span style="color: #0000ff;"&gt;for</span> (let i = 0; i < listeners.length; i++<span style="color: #000000;"&gt;) {
  const listener </span>=<span style="color: #000000;"&gt; listeners[i]
  listener()
}

</span><span style="color: #0000ff;"&gt;return</span><span style="color: #000000;"&gt; 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;"&gt; 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;"&gt;function</span><span style="color: #000000;"&gt; observeState() {
      </span><span style="color: #0000ff;"&gt;if</span><span style="color: #000000;"&gt; (observer.next) {
        observer.next(getState())
      }
    }

    observeState()
    const unsubscribe </span>=<span style="color: #000000;"&gt; outerSubscribe(observeStatE)
    </span><span style="color: #0000ff;"&gt;return</span><span style="color: #000000;"&gt; { unsubscribe }
  },[$$observable]() {
    </span><span style="color: #0000ff;"&gt;return</span> <span style="color: #0000ff;"&gt;this</span><span style="color: #000000;"&gt;
  }
}

}

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的使用姿势》

按注释上说 这只是一个 convenience method

你可以把 store.dispatch(MyActionCreators.doSomething()) 换成一个转成一个函数

我们使用 action 时 是先通过 actionCreator创建action 然后通过 dispatch 派发出去

通过 bindActionCreator(actionCreator,dispatch) 获得一个可以直接创建action并派发的函数

bindActionCreators 就是创建一个对象 每个属性都是一个 可以直接创建action并派发的函数

例:

action.increase = (info) => { type:'INCREASE'= (info) => { type:'DECREASE'bindActionCreators({
increase: action.increase,decrease: action.decrease
},dispatch)

<span style="color: #008000;">//<span style="color: #008000;"> 就可以获得:
<span style="color: #000000;">{
increase: (...args) =><span style="color: #000000;"> dispatch(action.increase(...args)),decrease: (...args) =><span style="color: #000000;"> dispatch(action.decrease(...args))
}

源码:

{ { dispatch(actionCreator.apply(<span style="color: #008000;">/<span style="color: #008000;">

  • Turns an object whose values are action creators,into an object with the
  • same keys,but with every function wrapped into a dispatch call so they
  • @H_691_371@may be invoked directly. This is just a convenience method,as you can call
  • store.dispatch(MyActionCreators.doSomething()) yourself just fine.
  • For convenience,you can also pass a single function as the first argument,* and get a function in return.
  • @param {Function|Object} actionCreators An object whose values are action
  • creator functions. One hAndy way to obtain it is to use ES6 import * as
  • syntax. You may also pass a single function.
  • @param {Function} dispatch The dispatch function available on your Redux
  • store.
  • @returns {Function|Object} The object mimicking the original object,but with
  • every action creator wrapped into the dispatch call. If you passed a
  • function as actionCreators,the return value will also be a single
  • function.
    <span style="color: #008000;">*/<span style="color: #000000;">
    export <span style="color: #0000ff;">default <span style="color: #0000ff;">function<span style="color: #000000;"> bindActionCreators(actionCreators,dispatch) {
    <span style="color: #008000;">//<span style="color: #008000;"> 如果 actionCreators 是一个函数 说明只有一个 actionCreator
    <span style="color: #0000ff;">if (<span style="color: #0000ff;">typeof actionCreators === 'function'<span style="color: #000000;">) {
    <span style="color: #0000ff;">return<span style="color: #000000;"> bindActionCreator(actionCreators,dispatch)
    }

<span style="color: #0000ff;">if (<span style="color: #0000ff;">typeof actionCreators !== 'object' || actionCreators === <span style="color: #0000ff;">null<span style="color: #000000;">) {
<span style="color: #0000ff;">throw <span style="color: #0000ff;">new<span style="color: #000000;"> Error(
bindActionCreators expected an object or a </span><span style="color: #0000ff;"&gt;function</span><span style="color: #000000;"&gt;,instead received ${ actionCreators </span>=== <span style="color: #0000ff;"&gt;null</span> ? 'null' : <span style="color: #0000ff;"&gt;typeof</span><span style="color: #000000;"&gt; actionCreators }. +<span style="color: #000000;">
Did you write </span>"import ActionCreators from" instead of "import * as ActionCreators from"?<span style="color: #000000;"&gt;
)
}

const keys =<span style="color: #000000;"> Object.keys(actionCreators)
const boundActionCreators =<span style="color: #000000;"> {}
<span style="color: #0000ff;">for (let i = 0; i < keys.length; i++<span style="color: #000000;">) {
const key =<span style="color: #000000;"> keys[i]
const actionCreator =<span style="color: #000000;"> actionCreators[key]
<span style="color: #0000ff;">if (<span style="color: #0000ff;">typeof actionCreator === 'function'<span style="color: #000000;">) {
boundActionCreators[key] =<span style="color: #000000;"> bindActionCreator(actionCreator,dispatch)
}
}
<span style="color: #0000ff;">return<span style="color: #000000;"> boundActionCreators
}

ymiddleware.js

这个应该是最难理解的部分 所以放到最后看>_<

个人理解,这个东西就是在dispatch前后做一些事情=.= 类似koa express的中间件嘛

以下参 源码中

@H_720_0@middleware 在dispatch和action之间提供一个第三方程序扩展点。

现在一步一步理解applymiddleware在做什么

首先,假设现在有一个需求,每次dispatch一个action时,都要打印action和state,像下面这样:

const action = addTodo('Use Redux'console.log('dispatching'<span style="color: #000000;">,action)
store.dispatch(action)
console.log('next state',store.getState())

但是不可能每一次都这样打印,也许直接修改dispatch就可以

const next == { console.log('dispatching'='next state'

呐,可能不止一个需求,现在我又想记录错误信息了。我们写两个方法,分别给dispatch添加自己想要的功能。

toaddLogging(storE) { const next == { console.log('dispatching'='next state'<span style="color: #0000ff;">function<span style="color: #000000;"> patchStoretoaddCrashReporTing(storE) {
const next
=<span style="color: #000000;"> store.dispatch
store.dispatch
= <span style="color: #0000ff;">function
<span style="color: #000000;"> dispatchAndReportErrors(action) {
<span style="color: #0000ff;">try
<span style="color: #000000;"> {
<span style="color: #0000ff;">return<span style="color: #000000;"> next(action)
} <span style="color: #0000ff;">catch<span style="color: #000000;"> (err) {
console.error('Caught an exception!'<span style="color: #000000;">,err)
Raven.captureException(err,{
extra: {
action,state: store.getState()
}
})
<span style="color: #0000ff;">throw<span style="color: #000000;"> err
}
}
}

patchStoretoaddLogging(storE)
patchStoretoaddCrashReporTing(storE)

但是这样并不好……很明显,我们在修改store的私有属性了,emmm……这是一个比较hack的方法……要改的优雅一点,把修改dispatch的部分封装起来。每一次返回新的dispatch,修改store的部分由 ymiddlewareBymonkeypatching 统一处理。

E) { const next = { { console.log('dispatching'<span style="color: #0000ff;">function<span style="color: #000000;"> applymiddlewareBymonkeypatching(store,middlewares) {
middlewares
=<span style="color: #000000;"> middlewares.slice()
middlewares.reverse()
<span style="color: #008000;">//
<span style="color: #008000;"> Transform dispatch function with each middleware.

middlewares.forEach(middleware =><span style="color: #000000;">
store.dispatch
=<span style="color: #000000;"> middleware(storE)
)
}

applymiddlewareBymonkeypatching(store,[logger,crashReporter])

但是这样还是不太好。dispatch是store的私有属性,我们却直接获取了。思我们为什么重写dispatch,因为我们在用多个中间件的时候,第一个中间件修改完dispatch,下一次修改应该是在前一个的基础之上,包裹上一次修改的dispatch。但其实,这也不是必要的,只要每一次传入上一次修改后的dispatch就可以了。

E) { toaddLogging(next) { { console.log('dispatching'='next state'

这里的next就是之前的中间件处理后的dispatch,我们不再获取store的私有属性了,改为用参数传递。然后在处理之后(logger(storE)(next))返回一个新的dispatch。

为什么这里要套两个函数而不是传入两个参数(store,next)呢,就相当于把这个函数柯里化了嘛……后面可以看到用处。

改成ES6的箭头函数

const logger = store => next => action =>{ console.log('dispatching'

说实话然简洁了,但是看起来一点都不直观……可能是我太菜了。嗯,这就是一个中间件的写法了。

可以简单的实现下 applymiddleware

ymiddleware(store,middlewares) { middlewares =s.slice() middlewares.reverse() let dispatch =s.forEach(middleware =>=E)(dispatch) ) ject.assign({},store,{ dispatch }) }

这样就可以最后使用 applymiddleware

import { createStore,combineReducers,applymiddleware } from 'redux'const todoApp =<span style="color: #000000;"> combineReducers(reducers)
const store =<span style="color: #000000;"> createStore(
todoApp,<span style="color: #008000;">//<span style="color: #008000;"> applymiddleware() tells createStore() how to handle middleware
<span style="color: #000000;"> applymiddleware(logger,crashReporter)
)

深入(meiyou)的理解之后 开始看applymiddleware.js源码

其中用到里 compose 要先看一下

compose.js

这个是函数式编程的一个……思想?应用?

将函数的嵌套调用写成组合   相当于   X)))

export default function compose(...funcs) { if (funcs.length === 0) { return arg => arg }

if (funcs.length === 1) {
return funcs[0]
}
// reduce的参数..
// reduce(function(accumulator,currentValue,currenTindex,array) {...})
return funcs.reduce((a,b) => (...args) => a(b(...args)))
}

/** 使用示例 **/

let a = x => 'a' + x + 'a'
let b = x => 'b' + x + 'b'
let c = x => 'c' + x + 'c'
let foo = compose(b,a)
console.log(foo('v')) // bcavACB
let bar = x => b(c(a(X)))
console.log(bar('v')) // bcavACB

 最后看applymiddleware.js

import compose from './compose'

<span style="color: #008000;">/<span style="color: #008000;">

  • Creates a store enhancer that applies middleware to the dispatch method

  • of the Redux store. This is hAndy for a variety of tasks,such as expressing

  • asynchronous actions in a concise mAnner,or logging every action payload.

  • See redux-thunk package as an example of the Redux middleware.

  • Because middleware is potentially asynchronous,this should be the first

  • store enhancer in the composition chain.

  • Note that each middleware will be given the dispatch and getState functions

  • as named arguments.

  • @param {...Function} middlewares The middleware chain to be applied.

  • @returns {Function} A store enhancer applying the middleware.
    <span style="color: #008000;">*/<span style="color: #000000;">
    export <span style="color: #0000ff;">default <span style="color: #0000ff;">function<span style="color: #000000;"> applymiddleware(...middlewares) {
    <span style="color: #0000ff;">return createStore => (...args) =><span style="color: #000000;"> {
    const store =<span style="color: #000000;"> createStore(...args)
    let dispatch = () =><span style="color: #000000;"> {
    <span style="color: #0000ff;">throw <span style="color: #0000ff;">new<span style="color: #000000;"> Error(
    Dispatching </span><span style="color: #0000ff;"&gt;while</span> construcTing your middleware is not allowed. +<span style="color: #000000;">
    Other middleware would not be applied to </span><span style="color: #0000ff;"&gt;this</span><span style="color: #000000;"&gt; dispatch.
    )
    }

    const middlewareAPI =<span style="color: #000000;"> {
    getState: store.getState,dispatch: (...args) =><span style="color: #000000;"> dispatch(...args)
    }
    const chain = middlewares.map(middleware =><span style="color: #000000;"> middleware(middlewareAPI))
    dispatch =<span style="color: #000000;"> compose(...chain)(store.dispatch)

    <span style="color: #0000ff;">return<span style="color: #000000;"> {
    ...store,dispatch
    }
    }
    }

applymiddleware([middlewares]) 就是返回一个函数 传入createStore,返回新的createStore,创建的store的dispatch是经过中间件加工的。

这里可以看到编写中间件嵌套两个函数的用处,先传入一个store,只需要再传入一个最新的dispatch就可以了,就是把dispatch用中间件轮流处理一下。这里使用了compose。

勉强看完源码。假装自己理解了这样子。

大佬总结

以上是大佬教程为你收集整理的Redux源码学习笔记全部内容,希望文章能够帮你解决Redux源码学习笔记所遇到的程序开发问题。

如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。
标签: