相信不少同窗跟我同樣對目前比較流行的前端庫的原理和實現 很感興趣,好比(react, vue, webpack, redux, react-redux, react-router...等等等), 可是一開始閱讀源碼的時候不免有些不順手, 本文以redux的源碼解讀爲例,爲你提供一些解讀源碼的思路,本文爲我解讀redux源碼的全過程,其中也會有一些彎路, 不過仍是分享給你們,畢竟本文倡導重在閱讀過程。前端
github上找到redux,clone到本地vue
目前最新版本: 4.0.1
複製代碼
打開項目, 個人習慣是先瞄一眼package,看一下相關依賴,有沒有peerDependencies等 react
想直接擼碼的同窗直接跳過這一步,看後面webpack
先用一個你比較熟悉的腳手架快速搭建一個react工程(由於後續會解析react-redux,因此直接用react工程),好比我選擇create-react-appgit
create-react-app redux-source-analyse
複製代碼
把redux中的src更名爲redux放在redux-source-analyse項目的src下, 接下來因爲做者考慮到閱讀react-redux的時候也須要有一個這樣的項目,直接把redux官網的todoList項目考到了該項目中,打開項目目錄是這樣的(其實redux源碼不須要使用這個todolist)github
根據常識,最開始咱們固然選擇看index.js文件web
嘿嘿,很簡單吧, 看下引用,沒有外部的包,而後返回了一個對象, 這個對象固然就是咱們引用的redux啦,編程
isCrushed.name !=='isCrushed'用來判斷是否壓縮過,若是不是production環境且壓縮了,給出warning
複製代碼
先來看看他是怎麼用的, 是function, 參數 initState, applyMiddleware可選redux
const store = createStore(rootReducer, initState, applyMiddleware(logger));
複製代碼
接着,過一下大致都是什麼東西api
基本閱讀步驟 (... throw new Error('....') ...)-> let xxx -> getState -> subscribe -> dispatch -> replaceReducer -> observable
import $$observable from 'symbol-observable'
import ActionTypes from './utils/actionTypes'
import isPlainObject from './utils/isPlainObject'
// 先看這裏, 就是咱們調用的createStore function了
export default function createStore(reducer, preloadedState, enhancer) {
// 若是 preloadedState和enhancer都爲function,不支持,throw new Error
// 咱們都知道[initState]爲object, [enhancer]爲function
if (
(typeof preloadedState === 'function' && typeof enhancer === 'function') ||
(typeof enhancer === 'function' && typeof arguments[3] === 'function')
) {
throw new Error(
'It looks like you are passing several store enhancers to ' +
'createStore(). This is not supported. Instead, compose them ' +
'together to a single function'
)
}
// preloadedState爲function enhancer爲undefined的時候說明initState沒有初始化, 可是有middleware
if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') {
enhancer = preloadedState // 把 preloadedState 賦值給 enhancer
preloadedState = undefined // preloadedState賦值undeifined
}
// debugger
// 若是參數enhancer存在
if (typeof enhancer !== 'undefined') {
// 若是enhancer存在,那他必須是個function, 不然throw Error哈
if (typeof enhancer !== 'function') {
throw new Error('Expected the enhancer to be a function.')
}
/** * 傳入符合參數類型的參數,就能夠執行 enhancer, * 可是這個return深深的吸引了我, 由於說明有applyMiddleware的時候後面的都不用看了 ??? 固然不可能 * 但是applyMiddleware實際上是必用項,因此猜測一下applyMiddleware強化store以後會enhancer賦值undefined,再次調用createStore * 上下打個debugger看一下執行順序(debugger位置以註釋),果真不出所料 * 好了, 假設咱們還不知道applyMiddleware()這個funcrion具體幹了什麼, * 只知道他作了一些處理而後從新調用了createStore而且enhancer參數爲undefined * 先記下,後續在看applyMiddleware, 由於咱們如今要看的是createStore * * */
// debugger
return enhancer(createStore)(reducer, preloadedState)
}
// debugger
// reducer要爲function
if (typeof reducer !== 'function') {
throw new Error('Expected the reducer to be a function.')
}
// 簡單過一下定義的變量
let currentReducer = reducer // 臨時reducer
let currentState = preloadedState // 臨時init state
let currentListeners = [] // 看名字,是個數組,起名Listeners,想到了什麼? 我想到的是監聽隊列和觀察者模式
let nextListeners = currentListeners // 淺拷貝下這個隊列
let isDispatching = false // 咱們很容易先假設isDispatching標誌是否正在執行dispatch
// 先看下各個函數的名字, 打眼一看getState,dispatch,subscribe都是比較熟悉的api
// subscribe,observable再加上定義的數組,應該確定是監聽隊列和觀察者模式
// 那咱們先看看比較熟悉且暴露出來的api好了先看 -> getState
// 其實這裏是保存一份訂閱快照
function ensureCanMutateNextListeners() {
// 不要忘了let nextListeners = currentListeners // 淺拷貝下這個隊列
// 判斷nextListeners和當前的currentListeners是否是一個引用
if (nextListeners === currentListeners) {
// 若是是一個引用的話深拷貝出來一個currentListeners賦值給nextListener
nextListeners = currentListeners.slice()
}
}
// store.getState()獲取當前的state
function getState() {
// dispatch中不能夠getState, 爲何?
// 由於dispatch是用來改變state的,爲了確保state的正確性(獲取最新的state),全部要判斷啦
if (isDispatching) {
throw new 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.'
)
}
// 肯定currentState是當前的state 看 -> subscribe
return currentState
}
// store.subscribe方法設置監聽函數,一旦觸發dispatch,就自動執行這個函數
// listener是一個callback function
function subscribe(listener) {
// 類型判斷
if (typeof listener !== 'function') {
throw new Error('Expected the listener to be a function.')
}
// 同理不能夠dispatch中
if (isDispatching) {
throw new Error(
'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.'
)
}
// 不肯定這個變量,猜想是訂閱標記,先往下看
let isSubscribed = true
// ensureCanMutateNextListeners幹啥的,點擊去看一下
ensureCanMutateNextListeners()
// push一個function,明顯的觀察者模式,添加一個訂閱函數
nextListeners.push(listener)
// 返回取消的function(unsubscribe)
return function unsubscribe() {
// 還記得let isSubscribed = true吧, 用來標記是否有listerner的
if (!isSubscribed) {
// 沒有直接return
return
}
// 同理
if (isDispatching) {
throw new Error(
'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.'
)
}
// 這裏解釋了isSubscribed,
isSubscribed = false
// 保存訂閱快照
ensureCanMutateNextListeners()
// 找到並刪除當前的listener
const index = nextListeners.indexOf(listener)
nextListeners.splice(index, 1)
}
}
// 發送一個action
function dispatch(action) {
// 看下util的isPlainObject
// acticon必須是由Object構造的函數, 不然throw Error
if (!isPlainObject(action)) {
throw new Error(
'Actions must be plain objects. ' +
'Use custom middleware for async actions.'
)
}
// 判斷action, 不存在type throw Error
if (typeof action.type === 'undefined') {
throw new Error(
'Actions may not have an undefined "type" property. ' +
'Have you misspelled a constant?'
)
}
// dispatch中不能夠有進行的dispatch
if (isDispatching) {
throw new Error('Reducers may not dispatch actions.')
}
try {
// 執行時標記爲true
isDispatching = true
// 執行reducer, 來,回憶一下reducer,參數state, action 返回值newState
// 這就是dispatch一個action能夠改變全局state的緣由
currentState = currentReducer(currentState, action)
} finally {
// 最終執行, isDispatching標記爲false, 即完成狀態
isDispatching = false
}
// 監聽隊列
// 全部的的監聽函數賦值給 listeners
const listeners = (currentListeners = nextListeners)
for (let i = 0; i < listeners.length; i++) {
const listener = listeners[i]
// 執行每個監聽函數
listener()
}
// 返回傳入的action
return action
// 到這裏dispatch方法就結束了, 咱們來思考總結一下, 爲何要用listeners
// 當dispatch發送一個規範的action時,會更新state
// 可是state改變了以後咱們須要作一些事情, 好比更新ui既數據驅動視圖
// (固然通常咱們使用react,react-redux的時候, 他們會幫咱們完成這些事情)
// 因此要提供一個監聽模式,固然還要有一個監聽函數subscribe, 保證dispatch和subscribe之間的一對多的模式
}
// 這是一個高級的api, 用於替換計算 state的reducer,不知道的同窗面壁去
// 哈哈開玩笑的確實很不經常使用, 官網也沒怎麼介紹
// redux 熱加載機制的時候用到了
function replaceReducer(nextReducer) {
// 既然是替換reducer, 類型要保持一直,不是function的滾遠點
if (typeof nextReducer !== 'function') {
throw new Error('Expected the nextReducer to be a function.')
}
// 當前的currentReducer更新爲參數nextReducer
currentReducer = nextReducer
// 和INIT的dispath相同,發送一個dispatch初始化state,代表一下是REPLACE
// 本身👀看一下utils方法的ActionTypes, 隨性的隨機數
dispatch({ type: ActionTypes.REPLACE })
}
// 不知道是幹什麼的, 先看看哪裏用到了, 全局收索一下
// 我TM!只有這一個地方有這個函數,並且沒被使用( [$$observable]: observable ), 就問你氣不氣?
// 固然不氣, 做爲不思進取的我以爲不用看這部分了, 算了,簡單的過一下, 恰好也不知道$$observable這個私有屬性的做用
// 好了, 全局搜索一下$$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. */
// 參數明顯是object
subscribe(observer) {
if (typeof observer !== 'object' || observer === null) {
throw new TypeError('Expected the observer to be an object.')
}
//獲取觀察着的狀態
function observeState() {
// 若是有next方法,吧回調state
if (observer.next) {
observer.next(getState())
}
}
observeState()
//返回取消訂閱的方法
const unsubscribe = outerSubscribe(observeState)
return { unsubscribe }
},
[$$observable]() {
return this // 猜想this應該是store
}
// observable方法簡單過一下,不作過多解釋,有了解的同窗,歡迎不吝賜教
}
}
// 有沒有想過,在使用redux的時候, 初始化的state哪來的
// 固然是本身先dispatch了一下
//reducer 返回其初始狀態
//初始化 store 裏的 state tree
dispatch({ type: ActionTypes.INIT })
// 這個就是返回的store嘛
return {
dispatch,
subscribe,
getState,
replaceReducer,
[$$observable]: observable
}
}
複製代碼
先過一下文件最吸引個人是export default function combineReducers,其餘幾個function好像都是用來拋出一些warning的, 因此先看這個combineReducers function(上面的先不要看👀,直接找combineReducers )
import ActionTypes from './utils/actionTypes'
import warning from './utils/warning'
import isPlainObject from './utils/isPlainObject'
/** * 先過一下文件最吸引個人是export default function combineReducers * 先看這個combineReducers function * */
function getUndefinedStateErrorMessage(key, action) {
const actionType = action && action.type
const actionDescription =
(actionType && `action "${String(actionType)}"`) || 'an action'
return (
`Given ${actionDescription}, reducer "${key}" returned undefined. ` +
`To ignore an action, you must explicitly return the previous state. ` +
`If you want this reducer to hold no value, you can return null instead of undefined.`
)
}
function getUnexpectedStateShapeWarningMessage( inputState, reducers, action, unexpectedKeyCache ) {
const reducerKeys = Object.keys(reducers)
const argumentName =
action && action.type === ActionTypes.INIT
? 'preloadedState argument passed to createStore'
: 'previous state received by the reducer'
if (reducerKeys.length === 0) {
return (
'Store does not have a valid reducer. Make sure the argument passed ' +
'to combineReducers is an object whose values are reducers.'
)
}
if (!isPlainObject(inputState)) {
return (
`The ${argumentName} has unexpected type of "` +
{}.toString.call(inputState).match(/\s([a-z|A-Z]+)/)[1] +
`". Expected argument to be an object with the following ` +
`keys: "${reducerKeys.join('", "')}"`
)
}
const unexpectedKeys = Object.keys(inputState).filter(
key => !reducers.hasOwnProperty(key) && !unexpectedKeyCache[key]
)
unexpectedKeys.forEach(key => {
unexpectedKeyCache[key] = true
})
if (action && action.type === ActionTypes.REPLACE) return
if (unexpectedKeys.length > 0) {
return (
`Unexpected ${unexpectedKeys.length > 1 ? 'keys' : 'key'} ` +
`"${unexpectedKeys.join('", "')}" found in ${argumentName}. ` +
`Expected to find one of the known reducer keys instead: ` +
`"${reducerKeys.join('", "')}". Unexpected keys will be ignored.`
)
}
}
function assertReducerShape(reducers) {
Object.keys(reducers).forEach(key => {
const reducer = reducers[key]
// reducer返回值
const initialState = reducer(undefined, { type: ActionTypes.INIT })
// undefined throw Error
if (typeof initialState === 'undefined') {
throw new Error(
`Reducer "${key}" returned undefined during initialization. ` +
`If the state passed to the reducer is undefined, you must ` +
`explicitly return the initial state. The initial state may ` +
`not be undefined. If you don't want to set a value for this reducer, ` +
`you can use null instead of undefined.`
)
}
// 很明顯assertReducerShape是用於reducer的規範
// 回到combineReducers
if (
typeof reducer(undefined, {
type: ActionTypes.PROBE_UNKNOWN_ACTION()
}) === 'undefined'
) {
throw new Error(
`Reducer "${key}" returned undefined when probed with a random type. ` +
`Don't try to handle ${ ActionTypes.INIT } or other actions in "redux/*" ` +
`namespace. They are considered private. Instead, you must return the ` +
`current state for any unknown actions, unless it is undefined, ` +
`in which case you must return the initial state, regardless of the ` +
`action type. The initial state may not be undefined, but can be null.`
)
}
})
}
// 用於合併reducer 通常是這樣combineReducers({a,b,c})
export default function combineReducers(reducers) {
// reducers中key的數組
const reducerKeys = Object.keys(reducers)
// 最終的reducer
const finalReducers = {}
for (let i = 0; i < reducerKeys.length; i++) {
// 接受當前的key
const key = reducerKeys[i]
// 若是不是生產環境, 當前的reducer是undefined會給出warning
if (process.env.NODE_ENV !== 'production') {
if (typeof reducers[key] === 'undefined') {
warning(`No reducer provided for key "${key}"`)
}
}
// reducer要是一個function
if (typeof reducers[key] === 'function') {
// 賦值給finalReducers
finalReducers[key] = reducers[key]
}
// 循環結束, 目的爲了給finalReducers賦值, 過慮了不符合規範的reudcer
}
// 符合規範的reducer的key數組
const finalReducerKeys = Object.keys(finalReducers)
// 意想不到的key, 先往下看看
let unexpectedKeyCache
if (process.env.NODE_ENV !== 'production') {
// production環境爲{}
unexpectedKeyCache = {}
}
let shapeAssertionError
try {
// 看這個function
assertReducerShape(finalReducers)
} catch (e) {
shapeAssertionError = e
}
// 返回function, 即爲createstore中的reducer參數既currentreducer
// 天然有state和action兩個參數, 能夠回createstore文件看看currentReducer(currentState, action)
return function combination(state = {}, action) {
// reducer不規範報錯
if (shapeAssertionError) {
throw shapeAssertionError
}
// 比較細緻的❌信息,順便看了一下getUndefinedStateErrorMessage,都是用於提示warning和error的, 不過多解釋了
if (process.env.NODE_ENV !== 'production') {
const warningMessage = getUnexpectedStateShapeWarningMessage(
state,
finalReducers,
action,
unexpectedKeyCache
)
if (warningMessage) {
warning(warningMessage)
}
}
let hasChanged = false
const nextState = {}
for (let i = 0; i < finalReducerKeys.length; i++) {
// 獲取finalReducerKeys的key和value(function)
const key = finalReducerKeys[i]
const reducer = finalReducers[key]
// 當前key的state值
const previousStateForKey = state[key]
// 執行reducer, 返回當前state
const nextStateForKey = reducer(previousStateForKey, action)
// 不存在返回值報錯
if (typeof nextStateForKey === 'undefined') {
const errorMessage = getUndefinedStateErrorMessage(key, action)
throw new Error(errorMessage)
}
// 新的state放在nextState對應的key裏
nextState[key] = nextStateForKey
// 判斷新的state是否是同一引用, 以檢驗reducer是否是純函數
hasChanged = hasChanged || nextStateForKey !== previousStateForKey
}
// 改變了返回nextState
return hasChanged ? nextState : state
}
/* * 新版本的redux這部分改變了實現方法 * 老版本的redux使用的reduce函數實現的 * 簡單例子以下 * function combineReducers(reducers) { * return (state = {}, action) => { * return Object.keys(reducers).reduce((currentState, key) => { * currentState[key] = reducers[key](state[key], action); * return currentState; * }, {}) * }; * } * * */
}
複製代碼
想必有點同窗還不知道這個api,我先看看bindActionCreators做用, 熟悉的同窗直接看實現
/** * * @export * @param {*} actionCreators 一個 action creator,或者一個 value 是 action creator 的對象。 * @param {*} dispatch 一個由 Store 實例提供的 dispatch 函數。 * @returns 一個與原對象相似的對象,只不過這個對象的 value 都是會直接 dispatch 原 action creator 返回的結果的函數。 * 若是傳入一個單獨的函數做爲 actionCreators,那麼返回的結果也是一個單獨的函數。 * * 場景: 唯一會使用到 bindActionCreators 的場景是當你須要把 action creator 往下傳到一個組件上, * 卻不想讓這個組件覺察到 Redux 的存在,並且不但願把 dispatch 或 Redux store 傳給它。 * / 複製代碼
function bindActionCreator(actionCreator, dispatch) {
// 閉包
return function() {
// 執行後返回結果爲傳入的actionCreator直接調用arguments
return dispatch(actionCreator.apply(this, arguments))
}
}
// 先看這裏 🔥🔥🔥
export default function bindActionCreators(actionCreators, dispatch) {
// actionCreators爲function
if (typeof actionCreators === 'function') {
return bindActionCreator(actionCreators, dispatch)
}
// 不是object throw Error
if (typeof actionCreators !== 'object' || actionCreators === null) {
throw new Error(
`bindActionCreators expected an object or a function, instead received ${ actionCreators === null ? 'null' : typeof actionCreators }. ` +
`Did you write "import ActionCreators from" instead of "import * as ActionCreators from"?`
)
}
// object 轉爲數組
const keys = Object.keys(actionCreators)
// 定義return 的props
const boundActionCreators = {}
for (let i = 0; i < keys.length; i++) {
// actionCreators的key 一般爲actionCreators function的name(方法名)
const key = keys[i]
// function => actionCreators工廠方法自己
const actionCreator = actionCreators[key]
if (typeof actionCreator === 'function') {
// 參數爲{actions:function xxx}是返回相同的類型
boundActionCreators[key] = bindActionCreator(actionCreator, dispatch)
}
}
// return 的props
return boundActionCreators
}
複製代碼
等等, 先解釋一下compose, 函數編程中的方法
Composes functions from right to left.
複製代碼
組合函數,將函數串聯起來從右到左執行 這裏的import compose from './compose'可能就是從函數編程移過來的
漲這樣:
compose(funcA, funcB, funcC) === compose(funcA(funcB(funcC())))
複製代碼
import compose from './compose'
/*** * * middleware既中間件,簡單說在redux中做爲擴展 dispatch 的惟一標準的方式。 * 不熟悉的同窗自行去api瞭解一下, 大體結構是這樣的 * middleware = (store) => (next) =>(action) =>{ [return next(action)]} * 爲了方便debugger咱們先本身寫一個簡單的logger middleware,看->src/index.js */
// applyMiddleware用來添加中間件,在修改數據的時候redux經過改造dispatch來實現中間件.
// 來吧,揭開applyMiddleware的神祕面紗
export default function applyMiddleware(...middlewares) {
// 返回一個名爲createStore的function
// 不知道你仍是否記得createStore.js開頭的這段代碼
/* if (typeof enhancer !== 'undefined') { if (typeof enhancer !== 'function') { throw new Error('Expected the enhancer to be a function.') } return enhancer(createStore)(reducer, preloadedState) } 嗯哼?對上了吧, 有applyMiddleware的時候直接先執行這裏, 沒繞過來的同窗debugger一下 * */
// 直接return createStore function
// 這裏咱們看下執行順序, 咱們寫一點僞代碼,每個變量是代碼中debugger的位置
/** * createStore.js * d1 = createStore(reducer, initstate, enhancer){ ... debugger if (typeof enhancer !== 'undefined')} * * d2 = if (typeof enhancer !== 'undefined') { if (typeof enhancer !== 'function') { throw new Error('Expected the enhancer to be a function.') } debugger return enhancer(createStore)(reducer, preloadedState) } * d3 = if (typeof enhancer !== 'undefined') {} debugger * * d4 = ... debugger const middlewareAPI = { // copy getState getState: store.getState, dispatch: (...args) => dispatch(...args) } d5 = ... debugger const store = createStore(...args)... * * 執行順序 * 建立store的首先是調用createStore(...applyMiddleware()) 大體發生了這樣的流程 * createStore(...applyMiddleware()) -> applyMiddleware() -> return function -> d1 -> d2 * 接下來 * return enhancer(createStore)(reducer, preloadedState) -> d5 -> createStore(...args)再次調用createStore -> d1 * 接下來走d3下面的store初始化 -> dispatch(init) -> d4 -> 組合middleware,合併new dispatch -> 返回加強的store */
return createStore => (...args) => {
// 保存createStore(reducer, initstate) || createStore(reducer), 賦值給store
// debugger
const store = createStore(...args)
// 定義了一個dispatch, 調用會 throw new Error(dispatching雖然構造middleware但不容許其餘middleware應用 )
let dispatch = () => {
throw new Error(
`Dispatching while constructing your middleware is not allowed. ` +
`Other middleware would not be applied to this dispatch.`
)
}
// debugger
// 定義middlewareAPI, 中間件中的store eg -> logger(store)
const middlewareAPI = {
// add getState
getState: store.getState,
// 添加dispatch幷包裝一個function, 參數爲(reducer, [initstate])
// 向下看一看middlewareAPI做爲參數被回調回去,不難理解, 告訴dispath不能再middleware插件中構造
dispatch: (...args) => dispatch(...args)
}
// 調用每個這樣形式的middleware = store => next => action =>{},
// 組成一個這樣[f(next)=>acticon=>next(action)...]的array,賦值給chain
const chain = middlewares.map(middleware => middleware(middlewareAPI))
// debugger
// compose看 -> compose.js文件
// compose(...chain)會造成一個調用鏈, next指代下一個函數的註冊, 這就是中間件的返回值要是next(action)的緣由
// 若是執行到了最後next就是原生的store.dispatch方法
dispatch = compose(...chain)(store.dispatch)
// 返回加強的store
return {
...store,
dispatch
}
}
}
複製代碼
最後的最後咱們去compose.js作一道題
// 其實這個頗有意思,是函數編程中的方法
// 咱們來作一到題
// 實現這個樣一個function -> compose(funcA, funcB, funcC) 形象爲 compose(funcA(funcB(funcC()))))
// 返回值爲一個(...args)=>(funcA(funcB(funcC(...args)))))
/** * * 你可能會這樣寫, 或者是for循環 * * function Compose(...funcs){ if (funcs.length === 0) { return args => args; } if (funcs.length === 1) { return funcs[0] } const arr = funcs; let firstFun = arr[0]; let len = arr.length; let i = 1; while(i !== len) { firstFun = firstFun(arr[i]); i++; } return firstFun; } * * */
// 好啦, 咱們看看優秀的答案吧 👇
export default function compose(...funcs) {
if (funcs.length === 0) {
return arg => arg
}
if (funcs.length === 1) {
return funcs[0]
}
// 是否是很巧妙
// 其實compose是redux做者從函數式編程中移過來的, 有興趣的同窗去了解一下
// 插個話, 由於compose的執行順序緣由, 因此有的middleware插件會要求要放在最後面
return funcs.reduce((a, b) => (...args) => a(b(...args)))
}
複製代碼
筆者以爲redux源碼並無很難,主要的精華是他的實現思想,咱們在來看看redux的三大原則
1.整個應用的state存儲在store中,有且只存在一個store。
2.store裏面的state是隻讀的,惟一改變state的方法就是派發(dispatch)一個動做(action)。
3.純函數(reducer)修改state,每次返回一個新的state,不能直接修改原對象。
以及咱們可不能夠本身寫一個簡單的redux
第一次寫博客, 竟然這麼累😫, 之後會堅持更新分享, O(∩_∩)O謝謝各位看官老爺, 歡迎交流,分享,指導。
附上github地址