react-redux提供connect和Provider将react和redux链接起来。react
// App.jsx import React from 'react' import { render } from 'react-dom' import { Provider } from 'react-redux' import createStore from 'redux' import reducer from './reducers' import Container from './Container' const store = createStore(reducer) const App = () => { return ( <Provider store={store}> <Container /> </Provider> ) } render(<App />, document.getElementById('app'))
容器组件git
// Container.jsx import React from 'react' import { connect } from 'react-redux' const mapStateToProps = (state, ownProps) => ({}) const mapDispatchToProps = (dispatch, ownProps) => ({}) export default connect(mapStateToProps, mapDispatchToProps)(Demo)
先看一看react-redux包的目录结构,其中es目录适用于ES模块导入,lib适用于commonjs模块导入github
Provider组件在Provider.js里面定义,仅有短短几十行代码,核心代码以下:redux
import { ReactReduxContext } from './Context'; function Provider(_ref) { var store = _ref.store, // 获取组件绑定的store context = _ref.context, children = _ref.children; // 获取子组件 // contextValue的值为{store, subscription} var contextValue = useMemo(function () { var subscription = new Subscription(store); subscription.onStateChange = subscription.notifyNestedSubs; return { store: store, subscription: subscription }; }, [store]); var previousState = useMemo(function () { return store.getState(); }, [store]); useEffect(function () { var subscription = contextValue.subscription; subscription.trySubscribe(); if (previousState !== store.getState()) { subscription.notifyNestedSubs(); } return function () { subscription.tryUnsubscribe(); subscription.onStateChange = null; }; }, [contextValue, previousState]); // 若是Provider组件上绑定了context就是用绑定的context,若是没有绑定context,就会本身生成context // children为嵌套在Provider里层的子组件 var Context = context || ReactReduxContext; return React.createElement(Context.Provider, { value: contextValue }, children); } export default Provider;
源码中使用了useMemo钩子函数,只有在第二个参数发生变化时,第一个参数函数才会执行,能够提高代码执行性能,避免每次组件渲染都要执行函数。详情能够去查看官网,这里制做简单介绍。segmentfault
var Context = context || ReactReduxContext; return React.createElement(Context.Provider, { value: contextValue }, children);
咱们看看这部分代码,若是Provider组件上绑定了context就是用绑定的context,若是没有绑定context,就会本身生成context。ReactReduxContext的生成在Context.js中:数组
import React from 'react'; export var ReactReduxContext = /*#__PURE__*/ React.createContext(null); if (process.env.NODE_ENV !== 'production') { ReactReduxContext.displayName = 'ReactRedux'; } export default ReactReduxContext;
有了context就能够向子组件提供store。架构
<Provider store={store}> <Container /> </Provider> // 等价于 <Provider store={store}> <Context.Provider value={{value: contextValue}}> <Container /> </Context.Provider> </Provider>
打开react devtool能够看到最外层组件为<Provider>,里层的子组件由<ReactRedux.Provider>组件包裹app
connect使用方式以下:dom
connect(mapStateToProps, mapDispatchToProps)(Demo)
能够猜测到connect(mapStateToProps, mapDispatchToProps)
这部分将返回一个高阶组件,这个高阶组件的做用就是将mapStateToProps返回的state和mapDispatchToProps返回的dispatch经过props传递给Demo。咱们经过源码来验证一下猜测是否正确。ide
connect函数在connect.js中实现,函数架子大概就是以下样子:
export function createConnect(_temp) { // coding... return function connect(mapStateToProps, mapDispatchToProps, mergeProps, _ref2) { // coding... return connectHOC(selectorFactory, options); }; } export default createConnect();
connectHOC函数执行返回的是一个高阶组件wrapWithConnect(WrappedComponent),它在connectAdvanced.js中实现,connectAdvanced这个函数就是connectHOC。
export default function connectAdvanced(selectorFactory, _ref) { // coding... return function wrapWithConnect(WrappedComponent) { // coding... function createChildSelector(store) { return selectorFactory(store.dispatch, selectorFactoryOptions); } // coding... function ConnectFunction(props) { // coding... // 获取context对象 var ContextToUse = useMemo(function () { return propsContext && propsContext.Consumer && isContextConsumer(React.createElement(propsContext.Consumer, null)) ? propsContext : Context; }, [propsContext, Context]); // 获取Context.Provider绑定的value值{store,subscription} var contextValue = useContext(ContextToUse); // 获取store var store = didStoreComeFromProps ? props.store : contextValue.store; // childPropsSelector返回一个函数(),接受store.getState()和props var childPropsSelector = useMemo(function () { return createChildSelector(store); }, [store]); // 这里执行childPropsSelector,将store.getState()和props传递进去,而后mapStateToProps接受到state和props,至于dispatch,在执行selectorFactory(store.dispatch, selectorFactoryOptions);就传递进去了。 var actualChildProps = usePureOnlyMemo(function () { if (childPropsFromStoreUpdate.current && wrapperProps === lastWrapperProps.current) { return childPropsFromStoreUpdate.current; } return childPropsSelector(store.getState(), wrapperProps); }, [store, previousStateUpdateResult, wrapperProps]); // actualChildProps获得的就是mapStateToProps返回的state,把它放在props中传递给UI组件 var renderedWrappedComponent = useMemo(function () { return React.createElement(WrappedComponent, _extends({}, actualChildProps, { ref: forwardedRef })); }, [forwardedRef, WrappedComponent, actualChildProps]); var renderedChild = useMemo(function () { // shouldHandleStateChanges控制是否应该订阅redux store中的state变化。 if (shouldHandleStateChanges) { // 订阅redux store中的state变化,返回ContextToUse.Provider嵌套组件 return React.createElement(ContextToUse.Provider, { value: overriddenContextValue }, renderedWrappedComponent); } // 不须要订阅redux store中的state变化就直接返回UI组件 return renderedWrappedComponent; }, [ContextToUse, renderedWrappedComponent, overriddenContextValue]); return renderedChild; } // React.memo用于建立一个纯函数组件,跟PureComponent同样,但React.memo做用于function component,而PureComponent做用于class component。使用纯函数组件最大的做用就是只有props变化时组件才会从新渲染,能够提升渲染性能。 var Connect = pure ? React.memo(ConnectFunction) : ConnectFunction; Connect.WrappedComponent = WrappedComponent; Connect.displayName = displayName; if (forwardRef) { var forwarded = React.forwardRef(function forwardConnectRef(props, ref) { return React.createElement(Connect, _extends({}, props, { forwardedRef: ref })); }); forwarded.displayName = displayName; forwarded.WrappedComponent = WrappedComponent; return hoistStatics(forwarded, WrappedComponent); } // hoistStatics是hoist-non-react-statics包的导出,用于将组件中非react自带的静态方法复制到另外一个组件。该包通常用于定义HOC中,由于当你给一个组件添加一个HOC时,原来的组件会被一个container的组件包裹,这意味着新的组件不会有原来组件任何静态方法。参考:https://zhuanlan.zhihu.com/p/36178509 return hoistStatics(Connect, WrappedComponent); }; }
connectHOC(selectorFactory, options)
中selectorFactory
函数传递到connectAdvanced(selectorFactory, _ref)
中,在ConnectFunction(props)
函数组件中调用createChildSelector(store)
,而后调用selectorFactory(store.dispatch, selectorFactoryOptions);
selectorFactory函数是connect中的核心API,它的实如今selectorFactory.js文件中,selectorFactory就是下面的导出。
export default function finalPropsSelectorFactory(dispatch, _ref2) { var initMapStateToProps = _ref2.initMapStateToProps, initMapDispatchToProps = _ref2.initMapDispatchToProps, initMergeProps = _ref2.initMergeProps, options = _objectWithoutPropertiesLoose(_ref2, ["initMapStateToProps", "initMapDispatchToProps", "initMergeProps"]); var mapStateToProps = initMapStateToProps(dispatch, options); var mapDispatchToProps = initMapDispatchToProps(dispatch, options); var mergeProps = initMergeProps(dispatch, options); if (process.env.NODE_ENV !== 'production') { verifySubselectors(mapStateToProps, mapDispatchToProps, mergeProps, options.displayName); } var selectorFactory = options.pure ? pureFinalPropsSelectorFactory : impureFinalPropsSelectorFactory; // return selectorFactory(mapStateToProps, mapDispatchToProps, mergeProps, dispatch, options); }
pureFinalPropsSelectorFactory函数实现:
export function pureFinalPropsSelectorFactory(mapStateToProps, mapDispatchToProps, mergeProps, dispatch, _ref) { var areStatesEqual = _ref.areStatesEqual, areOwnPropsEqual = _ref.areOwnPropsEqual, areStatePropsEqual = _ref.areStatePropsEqual; var hasRunAtLeastOnce = false; var state; var ownProps; var stateProps; var dispatchProps; var mergedProps; function handleFirstCall(firstState, firstOwnProps) { state = firstState; ownProps = firstOwnProps; stateProps = mapStateToProps(state, ownProps); dispatchProps = mapDispatchToProps(dispatch, ownProps); mergedProps = mergeProps(stateProps, dispatchProps, ownProps); hasRunAtLeastOnce = true; return mergedProps; } function handleNewPropsAndNewState() {} function handleNewProps() {} function handleNewState() {} function handleSubsequentCalls(nextState, nextOwnProps) { // coding... return function pureFinalPropsSelector(nextState, nextOwnProps) { return hasRunAtLeastOnce ? handleSubsequentCalls(nextState, nextOwnProps) : handleFirstCall(nextState, nextOwnProps); }; }
selectorFactory的做用就是将链接store的ConnectFunction组件中获取的state、props传递给MapStateToProps和将获取的dispatch传递给mapDispatchToProps。而后MapStateToProps和mapDispatchToProps的返回值会在ConnectFunction组件中使用props传递给UI组件。
wrapWithConnect(WrappedComponent)返回一个新的、链接到store的ConnectFunction(props)函数组件,该组件内部会根据shouldHandleStateChanges字段判断是否须要监听redux store中state的变化,若是须要就返回ContextToUse.Provider包裹UI组件的子组件,ContextToUse.Provider为组组件提供从新构造的overriddenContextValue,若是不须要监听redux store中state的变化,就返回UI组件为子组件。就如第一部份内容例子,Brother组件不须要state,Sister组件须要state,那么Sister组件就会用ContextToUse.Provider包裹着。整个组件架构就变成以下样子:
Memo表示该组件为纯函数组件
这三篇文章很是值得一读,参考:
https://github.com/MrErHu/blo...
https://juejin.im/post/59772a...
https://segmentfault.com/a/11...