一、 react-redux 和 redux是兩個東西。在做react項目的時候,一般用react-redux和redux搭配起來開發。redux主要是做數據、狀態的管理,而react-redux主要是方便數據redux在react使用。 二、源碼解析 1)、 入口文件index.js 2)、Pro ...
一、 react-redux 和 redux是兩個東西。在做react項目的時候,一般用react-redux和redux搭配起來開發。redux主要是做數據、狀態的管理,而react-redux主要是方便數據redux在react使用。
二、源碼解析
1)、 入口文件index.js
1 import Provider, { createProvider } from './components/Provider' 2 import connectAdvanced from './components/connectAdvanced' 3 import connect from './connect/connect' 4 5 /* 6 對外暴露的API 7 Provider, 8 createProvider, 9 connectAdvanced, 10 connect, 11 根據每個APi追溯其源頭 12 */ 13 export { Provider, createProvider, connectAdvanced, connect }
2)、Provider.js
1 import { Component, Children } from 'react' 2 import PropTypes from 'prop-types' 3 import { storeShape, subscriptionShape } from '../utils/PropTypes' 4 import warning from '../utils/warning' 5 6 let didWarnAboutReceivingStore = false 7 function warnAboutReceivingStore() { 8 if (didWarnAboutReceivingStore) { 9 return 10 } 11 didWarnAboutReceivingStore = true 12 13 warning( 14 '<Provider> does not support changing `store` on the fly. ' + 15 'It is most likely that you see this error because you updated to ' + 16 'Redux 2.x and React Redux 2.x which no longer hot reload reducers ' + 17 'automatically. See https://github.com/reduxjs/react-redux/releases/' + 18 'tag/v2.0.0 for the migration instructions.' 19 ) 20 } 21 // 對外暴露 createProvider 方法 。 22 export function createProvider(storeKey = 'store', subKey) { 23 const subscriptionKey = subKey || `${storeKey}Subscription` 24 25 // 定義一個Provider類 26 class Provider extends Component { 27 getChildContext() { 28 return { [storeKey]: this[storeKey], [subscriptionKey]: null } 29 } 30 31 constructor(props, context) { 32 super(props, context) 33 this[storeKey] = props.store; 34 } 35 // 其實就是頂層組件 36 render() { 37 return Children.only(this.props.children) 38 } 39 } 40 41 if (process.env.NODE_ENV !== 'production') { 42 Provider.prototype.componentWillReceiveProps = function (nextProps) { 43 if (this[storeKey] !== nextProps.store) { 44 warnAboutReceivingStore() 45 } 46 } 47 } 48 49 Provider.propTypes = { 50 store: storeShape.isRequired, 51 children: PropTypes.element.isRequired, 52 } 53 Provider.childContextTypes = { 54 [storeKey]: storeShape.isRequired, 55 [subscriptionKey]: subscriptionShape, 56 } 57 58 return Provider 59 } 60 61 // 對外暴露Provider 組件 createProvider() => Provider; 62 export default createProvider()
3)、connect.js
1 import connectAdvanced from '../components/connectAdvanced' 2 import shallowEqual from '../utils/shallowEqual' 3 import defaultMapDispatchToPropsFactories from './mapDispatchToProps' 4 import defaultMapStateToPropsFactories from './mapStateToProps' 5 import defaultMergePropsFactories from './mergeProps' 6 import defaultSelectorFactory from './selectorFactory' 7 8 /* 9 connect is a facade over connectAdvanced. It turns its args into a compatible 10 selectorFactory, which has the signature: 11 12 (dispatch, options) => (nextState, nextOwnProps) => nextFinalProps 13 14 connect passes its args to connectAdvanced as options, which will in turn pass them to 15 selectorFactory each time a Connect component instance is instantiated or hot reloaded. 16 17 selectorFactory returns a final props selector from its mapStateToProps, 18 mapStateToPropsFactories, mapDispatchToProps, mapDispatchToPropsFactories, mergeProps, 19 mergePropsFactories, and pure args. 20 21 The resulting final props selector is called by the Connect component instance whenever 22 it receives new props or store state. 23 */ 24 25 function match(arg, factories, name) { 26 for (let i = factories.length - 1; i >= 0; i--) { 27 const result = factories[i](arg) 28 if (result) return result 29 } 30 31 return (dispatch, options) => { 32 throw new Error(`Invalid value of type ${typeof arg} for ${name} argument when connecting component ${options.wrappedComponentName}.`) 33 } 34 } 35 36 function strictEqual(a, b) { return a === b } 37 38 // createConnect with default args builds the 'official' connect behavior. Calling it with 39 // different options opens up some testing and extensibility scenarios 40 // 對外暴露crateConnect方法 41 export function createConnect({ 42 connectHOC = connectAdvanced, 43 mapStateToPropsFactories = defaultMapStateToPropsFactories, 44 mapDispatchToPropsFactories = defaultMapDispatchToPropsFactories, 45 mergePropsFactories = defaultMergePropsFactories, 46 selectorFactory = defaultSelectorFactory 47 } = {}) { 48 // 返回一個connect函數。 接收 mapStateToProps, mapDispatchToProps, megeProps等等參數 49 return function connect( 50 mapStateToProps, 51 mapDispatchToProps, 52 mergeProps, 53 { 54 pure = true, 55 areStatesEqual = strictEqual, 56 areOwnPropsEqual = shallowEqual, 57 areStatePropsEqual = shallowEqual, 58 areMergedPropsEqual = shallowEqual, 59 ...extraOptions 60 } = {} 61 ) { 62 const initMapStateToProps = match(mapStateToProps, mapStateToPropsFactories, 'mapStateToProps') 63 const initMapDispatchToProps = match(mapDispatchToProps, mapDispatchToPropsFactories, 'mapDispatchToProps') 64 const initMergeProps = match(mergeProps, mergePropsFactories, 'mergeProps') 65 // 調用connectHOC方法 66 return connectHOC(selectorFactory, { 67 // used in error messages 68 methodName: 'connect', 69 70 // used to compute Connect's displayName from the wrapped component's displayName. 71 getDisplayName: name => `Connect(${name})`, 72 73 // if mapStateToProps is falsy, the Connect component doesn't subscribe to store state changes 74 shouldHandleStateChanges: Boolean(mapStateToProps), 75 76 // passed through to selectorFactory 77 initMapStateToProps, 78 initMapDispatchToProps, 79 initMergeProps, 80 pure, 81 areStatesEqual, 82 areOwnPropsEqual, 83 areStatePropsEqual, 84 areMergedPropsEqual, 85 86 // any extra options args can override defaults of connect or connectAdvanced 87 ...extraOptions 88 }) 89 } 90 } 91 92 export default createConnect()