redux源碼解析(深度解析redux+異步demo)

redux源碼解析

一、首先讓咱們看看都有哪些內容javascript

 


 

 

二、讓咱們看看redux的流程圖html

  

  Store:一個庫,保存數據的地方,整個項目只有一個java

      建立storereact

      Redux提供 creatStore 函數來生成 Storegit

// 引入redux
import { createStore } from 'redux';  

//建立Store 須要傳遞一個函數fn 這裏的fn是以後會說起的reducers
const store = createStore(fn);

 

  State:狀態,某時刻的數據便是Store的狀態github

      獲取狀態的方法是store.getState()json

 

  Action:行爲,它有一個不可或缺的type屬性
redux

      action還能夠攜帶其餘內容api

      咱們可使用action來改變State的值,數組

      從而將咱們須要的數據經過Action「運輸」到 Store;

 

  dispatch:發送action

      dispatch(action)接受一個action對象爲參數,並將它發送出去,

      Store接受Action,接受以後須要返回一個新的State(狀態)

 

  Reducer:處理器    

      dispatch(action)接受一個action對象爲參數,並將它發送出去,

      Store接受Action,接受以後須要返回一個新的State(狀態)

      而建立這個新的狀態的過程就是reducer

 


 

 

三、從isPlainObject.js開始

/**
 * @param {any} obj The object to inspect.
 * @returns {boolean} True if the argument appears to be a plain object.
 */
export default function isPlainObject(obj) {
  if (typeof obj !== 'object' || obj === null) return false

  let proto = obj
  while (Object.getPrototypeOf(proto) !== null) {
    proto = Object.getPrototypeOf(proto)
  }

  return Object.getPrototypeOf(obj) === proto
}

  · 這個函數的核心思想在於什麼呢?

  在於判斷一個值是否爲一個普通的對象

  此處的普通對象指的是直接經過字面量(let obj={})或者new Object()建立出來的對象

 

  · 那麼他是怎麼作判斷的呢?

if (typeof obj !== 'object' || obj === null) return false

  這行代碼排除掉確定不是對象的值

注意typeof null 的返回值爲 "object". 因此只使用 typeof obj !== 'object' 不能將 null 值排除掉. 
所以應使用 typeof obj !== 'object' || obj === null 進行判斷.

  再往下就是經過原型鏈判斷了.

  經過 while 不斷地判斷 Object.getPrototypeOf(proto) !== null 並執行,

  最終 proto 會指向 Object.prototype. 這時再判斷 Object.getPrototypeOf(obj) === proto,

  若是爲 true 的話就表明 obj 是經過字面量或調用 new Object() 所建立的對象了.

  Object.getPrototypeOf() 方法用於獲取一個對象的原型屬性指向的是哪一個對象. 

舉個🌰:
假設有一個構造器:function Fun(){}
建立一個對象:var f = new Fun()

Object.getPrototypeOf(f) 獲得的返回值
和訪問 f.__proto__ 是同樣的
這個值指向 Fun.prototype.

  

  假如一個對象是普通對象

  那麼這個對象的 __proto__ 必定是指向 Object.prototype 的,

  而非普通對象, 例如 f, 其 __proto__ 是指向其構造函數的 prototype 屬性.

  所以比較 Object.getPrototypeOf(obj) 與 proto 相等, 則斷定 obj 是普通對象.

 


  

四、接下來是createStore.js

 
 
//若是第二個參數爲方法且第三個參數爲空,則將兩個參數交換

if
(typeof preloadedState === 'function' && typeof enhancer === 'undefined') { enhancer = preloadedState preloadedState = undefined }

 //reducer須要是個方法
 
 if (typeof reducer !== 'function') {
    throw new Error('Expected the reducer to be a 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'
  )
}
 
let currentReducer = reducer  當前的reducer函數
let currentState = preloadedState   當前的state樹
let currentListeners = []  監聽函數列表
let nextListeners = currentListeners  監聽列表的一個引用
let isDispatching = false  是否正在dispatch
 

 

  裏面的幾個函數 

  getState()

//返回當前state樹
function
getState() { 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.' ) } return currentState }

 

  subscribe()

 
//這個函數用於給store添加監聽函數,把須要添加的監聽函數做爲參數傳入便可
//nextListeners 即爲目前的監聽函數列表,添加了以後,subscribe方法會返回一個unsubscribe()方法
//此方法用於註銷剛纔添加的監聽函數。
function subscribe(listener) { if (typeof listener !== 'function') { throw new Error('Expected the listener to be a function.') } 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() nextListeners.push(listener) return function unsubscribe() { if (!isSubscribed) { 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 = false ensureCanMutateNextListeners() const index = nextListeners.indexOf(listener) nextListeners.splice(index, 1) } }

 

  dispatch()

function dispatch(action) {
    //action必須是一個包含type的對象
    if (!isPlainObject(action)) {
      throw new Error(
        'Actions must be plain objects. ' +
        'Use custom middleware for async actions.'
      )
    }

    if (typeof action.type === 'undefined') {
      throw new Error(
        'Actions may not have an undefined "type" property. ' +
        'Have you misspelled a constant?'
      )
    }

    //若是正處於isDispatching狀態,報錯
    if (isDispatching) {
      throw new Error('Reducers may not dispatch actions.')
    }

    try {
      isDispatching = true
      //這裏就是調用咱們reducer方法的地方,返回一個新的state做爲currentState
      currentState = currentReducer(currentState, action)
    } finally {
      isDispatching = false
    }

    //調用全部的監聽函數
    const listeners = currentListeners = nextListeners
    for (let i = 0; i < listeners.length; i++) {
      const listener = listeners[i]
      listener()
    }

    return action
  }

它只是執行了當前的reducer方法,
而後把當前的state和你在調用dispatch時傳入的action做爲參數,
返回的值就是新的currentState。
從這裏咱們也能夠看出,改變state的代碼邏輯就在reducer方法中,
在這些執行完以後,dispatch方法會遍歷當前的監聽列表,並執行全部的監聽函數。
 

 

  replaceReducer()
  function replaceReducer(nextReducer) {
    if (typeof nextReducer !== 'function') {
      throw new Error('Expected the nextReducer to be a function.')
    }

    currentReducer = nextReducer
    dispatch({ type: ActionTypes.REPLACE })
  }
替換reducer以後從新初始化狀態樹

 

  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. */ subscribe(observer) { if (typeof observer !== 'object' || observer === null) { throw new TypeError('Expected the observer to be an object.') }       
      
    //觀察者模式的鏈式結構,傳入當前的state
function observeState() {
          if (observer.next) {
            observer.next(getState())
          }
        }

        observeState()
        const unsubscribe = outerSubscribe(observeState)
        return { unsubscribe }
      },

      [$$observable]() {
        return this
      }
    }
  }

 


 

 

五、接下來就是compose.js

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

  if (funcs.length === 1) {
    return funcs[0]
  }

  return funcs.reduce((a, b) => (...args) => a(b(...args)))
}

reduce方法接受2個參數,第一個參數是一個callback函數,第二個是一個初始值initValue
第一個函數有四個參數

  • previousValue: 上一次調用callback時返回的值
  • currentValue: 正在處理的數組元素
  • index: 正在處理的數組元素下標
  • array: 被處理的數組

若是有initValue,initValue將做爲第一次的previousValue,若沒有,則數組第一個元素將做爲previousValue,

後面一個元素將做爲currentValue,而後執行callback的函數體,將返回的值做爲previousValue,

將下一個元素做爲currentValue,一直到最後一個數組最後一個元素執行完位置,再返回最終的結果。

好比有一個數組arr=[1,2,3,4,5],咱們使用reduce來求和:

let sum = [1,2,3,4,5].reduce((a,b)=>a+b);

它巧妙的地方在於數組的每一個元素都是函數,

callback返回一個複合函數做爲previousValue,在reduce方法執行完以後,

也就返回了一個將整個數組中全部函數串式調用的一個函數。

 


 

 

六、而後是applyMiddleware.js

export default function applyMiddleware(...middlewares) {

//return一個函數,能夠接收createStore方法做爲參數
//給返回的store的dispatch方法再進行一次包裝
return createStore => (...args) => { const store = createStore(...args) let dispatch = () => { throw new Error( `Dispatching while constructing your middleware is not allowed. ` + `Other middleware would not be applied to this dispatch.` ) }
  
  //暴露兩個方法給外部
const middlewareAPI
= { getState: store.getState, dispatch: (...args) => dispatch(...args) }

  
  //傳入middlewareAPI參數並執行每個外部函數,返回結果匯聚成數組
const chain
= middlewares.map(middleware => middleware(middlewareAPI))
  //用到了上面的compose方法

  dispatch
= compose(...chain)(store.dispatch) return { ...store, dispatch } } }

  

  還記得剛纔createStore方法中的enhancer參數嗎?
  applyMiddleware就是用來建立enhancer函數的。
  官方的註釋中提到了redux-thunk,
  就是使用applyMiddleware的一個很好的例子,
  咱們結合它的代碼來看能夠更好的理解,下面是它的代碼:
 
function createThunkMiddleware(extraArgument) {
  return ({ dispatch, getState }) => next => action => {
    if (typeof action === 'function') {
      return action(dispatch, getState, extraArgument);
    }

    return next(action);
  };
}

const thunk = createThunkMiddleware();
thunk.withExtraArgument = createThunkMiddleware;

export default thunk;

 

  

  最終export了一個接受{ dispatch, getState }做爲參數的function thunk,

  這個thunk方法也就是傳給applyMiddleware方法的參數,

  此時的middlewares只有thunk一個方法,

  那麼applyMiddleware中的chain也就很顯然的是執行了thunk方法後返回的結果,

  咱們再看redux-thunk的代碼,返回了一個接受next做爲參數的方法!

  applyMiddleware的下一行,

  dispatch = compose(...chain)(store.dispatch),

  chain只有一個function,因此這裏能夠忽略compose,

  那麼這一句就是將store.dispatch 做爲next參數傳給了剛纔的方法A,

  終於,方法A返回了咱們熟悉的dispatch方法。


  可是注意,此時的dispatch方法仍是原來的dispatch方法嗎?

  它已經不是原來的它了。通過thunk方法的包裝,早已物是人非。

  咱們來看一下redux-thunk的代碼,第三行以後的4行,

  若是dispatch方法接受的參數不是一個function,

  那麼這個dispatch就和普通的dispatch沒什麼不一樣,

  但若是此時的action是一個方法,那麼就會執行此方法,且第一個參數是store.dispatch。

  這意味着咱們的action建立函數再也不只能建立一個包含type的Object,而能夠是一個方法。

  你可能會問有什麼用呢?當你在action中須要一個異步操做,並須要在回調中改變state的狀態的時候,這就是一個絕佳的解決方案。

  因此說,applyMiddleware實際上作了一件事,就是根據外部函數(中間件函數)包裝原來的dispatch函數,而後將新的dispatch函數暴露出去。

  再回頭去看createStore.jsx中的 return enhancer(createStore)(reducer, preloadedState)這句代碼,是否是明白了不少事情?




 
 
七、combineReducers.js
//很簡單卻很關鍵,我就不解釋了~
function bindActionCreator(actionCreator, dispatch) {
  return (...args) => dispatch(actionCreator(...args))
}

  /**
   * 將action與dispatch函數綁定,生成直接能夠觸發action的函數,
   * 能夠將第一個參數對象中全部的action都直接生成能夠直接觸發dispatch的函數
   * 而不須要一個一個的dispatch,生成後的方法對應原來action生成器的函數名
   * */
export default function bindActionCreators(actionCreators, dispatch) {
  if (typeof actionCreators === 'function') {
    return bindActionCreator(actionCreators, dispatch)
  }
    
  //actionCreators必須爲object類型
  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"?`
    )
  }

  const keys = Object.keys(actionCreators)
  const boundActionCreators = {}
  for (let i = 0; i < keys.length; i++) {
    const key = keys[i]
    const actionCreator = actionCreators[key]
    
    //給actionCreators的每個成員都綁定dispatch方法生成新的方法,
    //而後注入新的對象中,新方法對應的key即爲原來在actionCreators的名字
    if (typeof actionCreator === 'function') {
      boundActionCreators[key] = bindActionCreator(actionCreator, dispatch)
    } else {
      warning(`bindActionCreators expected a function actionCreator for key '${key}', instead received type '${typeof actionCreator}'.`)
    }
  }
  return boundActionCreators

這個方法主要的做用就是將action與dispatch函數綁定,生成直接能夠觸發action的函數。代碼比較簡單註釋也比較明白,就過去了~

 


 

 

八、bindActionCreators.js

//根據key和action生成錯誤信息
function getUndefinedStateErrorMessage(key, action) {
  //...
}

//一些警告級別的錯誤
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'

  //判斷reducers是否爲空數組
  //判斷state是不是對象
  //給state中存在而reducer中不存在的屬性添加緩存標識並警告
  //...
}


//這個方法用於檢測用於組合的reducer是不是符合redux規定的reducer
function assertReducerSanity(reducers) {
  Object.keys(reducers).forEach(key => {
    const reducer = reducers[key]
    //調用reducer方法,undefined爲第一個參數
    //使用前面說到過的ActionTypes.INIT和一個隨機type生成action做爲第二個參數
    //若返回的初始state爲undefined,則這是一個不符合規定的reducer方法,拋出異常
    //...
  })
}

export default function combineReducers(reducers) {
  const reducerKeys = Object.keys(reducers) //全部的鍵名
  const finalReducers = {}
  for (let i = 0; i < reducerKeys.length; i++) {
    const key = reducerKeys[i]

    if (process.env.NODE_ENV !== 'production') {
      if (typeof reducers[key] === 'undefined') {
        warning(`No reducer provided for key "${key}"`)
      }
    }

    //finalReducers是過濾後的reducers,它的每個屬性都是一個function
    if (typeof reducers[key] === 'function') {
      finalReducers[key] = reducers[key]
    }
  }

  const finalReducerKeys = Object.keys(finalReducers)

  let unexpectedKeyCache
  if (process.env.NODE_ENV !== 'production') {
    unexpectedKeyCache = {}
  }

  let sanityError

  //檢測每一個reducer是不是符合標準的reducer
  try {
    assertReducerSanity(finalReducers)
  } catch (e) {
    sanityError = e
  }

  return function combination(state = {}, action) {
    if (sanityError) {
      throw sanityError
    }

    //若是不是成產環境,作一些警告判斷
    if (process.env.NODE_ENV !== 'production') {
      const warningMessage = getUnexpectedStateShapeWarningMessage(state, finalReducers, action, unexpectedKeyCache)
      if (warningMessage) {
        warning(warningMessage)
      }
    }

    let hasChanged = false
    const nextState = {} //下一個state樹

    //遍歷全部reducers,而後將每一個reducer返回的state組合起來生成一個大的狀態樹,因此任何action,redux都會遍歷全部的reducer
    for (let i = 0; i < finalReducerKeys.length; i++) {
      const key = finalReducerKeys[i]
      const reducer = finalReducers[key]
      const previousStateForKey = state[key]
      const nextStateForKey = reducer(previousStateForKey, action)

      //若是此reducer返回的新的state是undefined,拋出異常
      if (typeof nextStateForKey === 'undefined') {
        const errorMessage = getUndefinedStateErrorMessage(key, action)
        throw new Error(errorMessage)
      }
      nextState[key] = nextStateForKey
      hasChanged = hasChanged || nextStateForKey !== previousStateForKey
    }
    //若是當前action對應的reducer方法執行完後,該處數據沒有變化,則返回原來的流程樹
    return hasChanged ? nextState : state
  }
}

 


 

九、Demo詳細解析

 

新建一個react項目

 

我項目大概長這個樣子

 


 

 

9.1先給本身創建一個Store庫,這就是你redux數據的倉庫了

  store文件夾下有兩個文件,

  reducers,把你各個頁面的reducer匯合起來,給他們起不一樣的好聽的名字,

  我這裏只有一個home頁面

import { combineReducers } from 'redux'

import home from 'pages/home/reducer'

export default combineReducers({
    home
})

  另外一個文件是index.js

  主要是用來建立你的庫,建立庫的時候我這裏用到了兩個參數並且還引入了一箇中間件

沒有中間件的Redux的過程是:,
而有了中間件的過程就是,
使用中間件咱們能夠對action也就是對dispatch方法進行裝飾,
咱們能夠用它來實現異步action、打印日誌、錯誤報告等功能。

import { createStore, applyMiddleware } from 'redux' import thunk from 'redux-thunk' import reducers from './reducers' const store = createStore(reducers, applyMiddleware(thunk)) export default storeaction -> reduceraction -> middleware -> reducer

   這時候你能夠回頭去看看上面對redux-thunk源碼的解析,  

   你會發現這樣包裝後的dispatch很是可愛

   當你在action中須要一個異步操做,並須要在回調中改變state的狀態的時候,這就是一個絕佳的解決方案。

 


 

9.二、給你的組件注入這個庫

  在index.html裏

  

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import { Provider } from 'react-redux'
import store from './store'

ReactDOM.render(
    <Provider store={store}>
        <App />
    </Provider>, 
    document.getElementById('root')
);

  咱們能夠參考源碼哦

//這裏須要傳store因此咱們使用Provider的時候把store傳入

//那麼咱們引入了Provider它爲咱們作了什麼呢?

export function createProvider(storeKey = 'store') { const subscriptionKey = `${storeKey}Subscription` class Provider extends Component {

    //將外部的store對象放入context對象中,使子孫組件上的connect能夠直接訪問到context對象中的store。
getChildContext() {
return { [storeKey]: this[storeKey], [subscriptionKey]: null } }
     //constructor是Provider初始化時,用於獲取props的store對象
constructor(props, context) { super(props, context)
this[storeKey] = props.store; }
     //首先,它把它引入的內容所有變成它的子級元素,
     //而且因爲它處於整個index.html的最外層
     //因此被它包裹的每個元素均可以接收redux的store數據做爲props
  render() {
return Children.only(this.props.children)
                        //this.props.children用於獲取當前組件的全部子組件
                        //children.only表示用於獲取僅有的一個子組件,沒有或者超過一個均會報錯.
                        //因此注意: 確保Provider組件的直接子級爲單個封閉元素,切勿多個組件平行放置
                        //引伸問題:當這個項目須要用到router時該怎麼辦?把router包在倒數第二層,Provider在最外層 } }
if (process.env.NODE_ENV !== 'production') { Provider.prototype.componentWillReceiveProps = function (nextProps) { if (this[storeKey] !== nextProps.store) { warnAboutReceivingStore() } } } Provider.propTypes = { store: storeShape.isRequired, children: PropTypes.element.isRequired, } Provider.childContextTypes = { [storeKey]: storeShape.isRequired, [subscriptionKey]: subscriptionShape, } return Provider } export default createProvider()

 

 


 

 

9.三、page下的home頁面有三個文件

  actionTypes.js

  

export const GET_HOME_DATA = 'home/get_home_data'

  你起什麼名字均可以,只要不重複,你開心就行了。

  這個名字貫穿了一條修改路線,你會發現接下來你的actionCreator.js和你的reducer.js裏都用到了這個名字,不一樣的名字對應不一樣的數據操做,記號它,爲了便於記號它,我爲它專門設置了本身的actionType.js

  

  actionCreator.js

import { GET_HOME_DATA } from './actionTypes'

export const loadHomeDataSync = (home) => {
    return {
      type: GET_HOME_DATA,
      home
    }
}
//先異步獲取數據,爲了不麻煩我這裏用mock數據代替了
//再同步返回獲取到的數據
export const loadHomeDataAsync
= (dispatch) => { return () => { fetch('/mock/data.json') .then(response => response.json()) .then(result => { dispatch(loadHomeDataSync(result.data)) }) } }

  

  reducer.js

    

  //給你要用的數據設置初值,而且當新的數據來了之後,對數據作你想要的處理
  //我這裏是當原數據爲空,state爲新數據,原數據有的話,和新數據進行合併返回一個新的state

import { GET_HOME_DATA } from './actionTypes' const defaultState = { home:null } export default (state=defaultState, action) => { if (action.type === GET_HOME_DATA) { if(!!state.home){ return { home: [...state.home,...action.home] } } else{ return { ...state, home: [...action.home] } } } return state }

  


 

9.4  page下的view下的Home.js

import React, { Component } from 'react';

import { loadHomeDataAsync } from '../actionCreator'

//connect做用:鏈接React組件與 Redux store

import { connect } from
'react-redux' const mapState = (state) => { return { home: state.home.home } } const mapDispatch = (dispatch) => { return { loadCategories () { dispatch(loadHomeDataAsync(dispatch)) } } } class Home extends Component { componentDidMount(){ this.props.loadCategories()
    //在這裏調用,固然,你想在哪調用均可以 } render() { console.log(
this.props.home) return ( <div>home</div> ); } } export default connect(mapState,mapDispatch)(Home);
//記得在這裏把他們connect起來

  那麼connect他究竟爲咱們作了什麼呢?

  爲何connect後面跟兩個括號?

  它的基礎做用是:

    a、從context裏獲取store
    b、在componentWillMount 裏經過mapStateToProps獲取stateProp的值
    c、在componentWillMount 裏經過mapDispatchToProps獲取dispatchProps的值
    d、在componentWillMount 裏訂閱store的變化
    e、將得到的stateProp,dispatchProps,還有自身的props合成一個props傳給下面的組件

 

  參考源碼:

export function createConnect({
  connectHOC = connectAdvanced,
  mapStateToPropsFactories = defaultMapStateToPropsFactories,
  mapDispatchToPropsFactories = defaultMapDispatchToPropsFactories,
  mergePropsFactories = defaultMergePropsFactories,
  selectorFactory = defaultSelectorFactory
} = {}) {
  return function connect(
    mapStateToProps,
    mapDispatchToProps,
    mergeProps,
    {
      pure = true,
      areStatesEqual = strictEqual,
      areOwnPropsEqual = shallowEqual,
      areStatePropsEqual = shallowEqual,
      areMergedPropsEqual = shallowEqual,
      ...extraOptions
    } = {}
  ) {
    const initMapStateToProps = match(mapStateToProps, mapStateToPropsFactories, 'mapStateToProps')
    const initMapDispatchToProps = match(mapDispatchToProps, mapDispatchToPropsFactories, 'mapDispatchToProps')
    const initMergeProps = match(mergeProps, mergePropsFactories, 'mergeProps')

    return connectHOC(selectorFactory, {
      // used in error messages
      methodName: 'connect',

       // used to compute Connect's displayName from the wrapped component's displayName.
      getDisplayName: name => `Connect(${name})`,

      // if mapStateToProps is falsy, the Connect component doesn't subscribe to store state changes
      shouldHandleStateChanges: Boolean(mapStateToProps),

      // passed through to selectorFactory
      initMapStateToProps,
      initMapDispatchToProps,
      initMergeProps,
      pure,
      areStatesEqual,
      areOwnPropsEqual,
      areStatePropsEqual,
      areMergedPropsEqual,

      // any extra options args can override defaults of connect or connectAdvanced
      ...extraOptions
    })
  }
}
  
connect接收四個參數:mapStateToProps,mapDispatchToProps,mergeProps,optipons
返回:一個注入了 state 和 action creator 的 React 組件


  mapStateToProps

  傳入:state,ownProps
  輸出:stateProps

 
    

   

   mapDispatchToProps


這個很是關鍵,若是定義了這個參數,就會監聽redux store的變化,沒有的話,就不會。
該回調函數必須返回一個純對象,這個對象會與組件的 props 合併。
同時,若是指定了第二個ownProps,這個參數的值爲傳入到組件的props,只要組件接受到新的props,mapStateToProps也會被調用



   mergeProps(function)

 
    

   stateProps,dispatchProps,自身的props將傳入到這個函數中。
   默認是Object.assign({}, ownProps, stateProps, dispatchProps)

 

  完整:

connect(mapStateToProps, mapDispatchToProps, mergeProps)(MyComponent)
 
    

 

 
   

 

 結果

 

  

demo地址:

https://github.com/yangTwo100/reduxAsync_demo

 

 

 

 

 

 

之後再更。 

相關文章
相關標籤/搜索