以前学习了Redux,而后发现有Redux的地方几乎都少不了react-redux这个库,它能够说是创建了React组件和Redux之间的桥梁。因此我特意学习了react-redux,以为颇有必要记录一下。react
若是不用react-redux的话,咱们想在React组件中使用Redux,就不得不引入store,使用store.dispatch(action)去分派action,间接地改变状态。乍一看,这样没什么问题啊,是的,若是只是一个组件的话这样确实没什么问题。可是,试想,若是该组件的子组件也想用名为xxx的state的话,岂不是又得引入store,而后又是像父组件那样一套流程下来,这样确实生效,可是显得代码很是的臃肿,可维护性不好,由于作了不少重复的工做。可是若是咱们引入一个容器组件,这个组件可使用props的方式将state和dispatch传递给子组件,这样就省去了不少重复的工做。这时,react-redux库就发挥做用了,创建起React和store的桥梁,能够将store和dispatch映射给props,这样React的组件就能够经过props将state和dispatch向下传递;或者可使用Provider提供一个context,将store无限制向下传递给子孙组件。redux
先说一下react-redux作了什么:ide
提供connect高阶组件,主要作了两件事:函数
当我了解到react-redux的大体功能以后,我脑海里立马产生了三个疑问,分别是:学习
先来看Provider.js的源码:ui
function Provider({ store, context, children }) { const contextValue = useMemo(() => { //声明一个Subscription实例。订阅,监听state变化来执行listener,都由实例来完成 const subscription = new Subscription(store) //绑定监听,当state变化时,通知订阅者更新页面,实际上也就是在connect过程当中被订阅到react-redux的subscription对象上的更新函数 subscription.onStateChange = subscription.notifyNestedSubs return { store, subscription } }, [store]) //获取当前的store的state,做为上一次的state,将会在组件挂载完毕后, //与store新的state比较,不一致的话更新Provider组件 const previousState = useMemo(() => store.getState(), [store]) useEffect(() => { //这会在组件渲染以后执行,因此这个时候contextValue已经返回 //在组件挂载完毕后,订阅更新。 const { subscription } = contextValue //contextValue = { store, subscription } //这里先理解为最开始的时候须要订阅更新函数,便于在状态变化的时候执行更新函数,至关因而注册了一个监听,在监听state的变化。 subscription.trySubscribe() //若是先后的store中的state有变化,那么就去更新Provider组件 if (previousState !== store.getState()) { subscription.notifyNestedSubs() } return () => { subscription.tryUnsubscribe() subscription.onStateChange = null } }, [contextValue, previousState]) const Context = context || ReactReduxContext return <Context.Provider value={contextValue}>{children}</Context.Provider> } if (process.env.NODE_ENV !== 'production') { //propTypes仅在开发模式下进行检查 Provider.propTypes = { store: PropTypes.shape({ subscribe: PropTypes.func.isRequired, dispatch: PropTypes.func.isRequired, getState: PropTypes.func.isRequired }), context: PropTypes.object, children: PropTypes.any } } export default Provider
因此结合代码看这个问题:Provider是怎么把store放入context中的,很好理解。
Provider最主要的功能是从props中获取咱们传入的store,并将store做为context的其中一个值,向下层组件下发。this
可是,一旦store变化,Provider要有所反应,以此保证将始终将最新的store放入context中。因此这里要用订阅来实现更新。天然引出Subscription类,经过该类的实例,将onStateChange监听到一个可更新UI的事件this.notifySubscribers上:spa
subscription.onStateChange = this.notifySubscribers
组件挂载完成后,去订阅更新,至于这里订阅的是什么,要看Subscription的实现。这里先给出结论:本质上订阅的是onStateChange,实现订阅的函数是:Subscription类以内的trySubscribe。code
this.state.subscription.trySubscribe()
再接着,若是先后的state不同,那么就去通知订阅者更新,onStateChange就会执行,Provider组件就会执行下层组件订阅到react-redux的更新函数。当Provider更新完成(componentDidUpdate),会去比较一下先后的store是否相同,若是不一样,那么用新的store做为context的值,而且取消订阅,从新订阅一个新的Subscription实例。保证用的数据都是最新的。component
//若是先后的store中的state有变化,那么就去更新Provider组件 if (previousState !== store.getState()) { subscription.notifyNestedSubs() } return () => { subscription.tryUnsubscribe() subscription.onStateChange = null }
//未完成...