随笔 - 49  文章 - 0  评论 - 28  阅读 - 18万 

redux源码解析

1、首先让我们看看都有哪些内容

 


 

 

2、让我们看看redux的流程图

  

  Store:一个库,保存数据的地方,整个项目只有一个

      创建store

      Redux提供 creatStore 函数来生成 Store

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

//创建Store 需要传递一个函数fn 这里的fn是之后会提及的reducers
const store = createStore(fn);

 

  State:状态,某时刻的数据即是Store的状态

      获取状态的方法是store.getState()

 

  Action:行为,它有一个不可或缺的type属性

      action还可以携带其他内容

      我们可以使用action来改变State的值,

      从而将我们需要的数据通过Action“运输”到 Store;

 

  dispatch:发送action

      dispatch(action)接受一个action对象为参数,并将它发送出去,

      Store接受Action,接受之后需要返回一个新的State(状态)

 

  Reducer:处理器    

      dispatch(action)接受一个action对象为参数,并将它发送出去,

      Store接受Action,接受之后需要返回一个新的State(状态)

      而创建这个新的状态的过程就是reducer

 


 

 

3、从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 是普通对象.

 


  

4、接下来是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
      }
    }
  }
复制代码

 


 

 

5、接下来就是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方法执行完之后,

也就返回了一个将整个数组中所有函数串式调用的一个函数。

 


 

 

6、然后是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)这句代码,是不是明白了很多事情?




 
 
7、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的函数。代码比较简单注释也比较明白,就过去了~
复制代码

 


 

 

8、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
  }
}
复制代码

 


 

9、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 -> reducer
而有了中间件的过程就是action -> middleware -> reducer
使用中间件我们可以对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 store
复制代码

   这时候你可以回头去看看上面对redux-thunk源码的解析,  

   你会发现这样包装后的dispatch非常可爱

   当你在action中需要一个异步操作,并需要在回调中改变state的状态的时候,这就是一个绝佳的解决方案。

 


 

9.2、给你的组件注入这个库

  在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.3、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

 

 

 

 

 

 

以后再更。 

 

 

 

 

 
posted on   薛小白  阅读(4064)  评论(4编辑  收藏  举报
努力加载评论中...
点击右上角即可分享
微信分享提示