以前學習了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 }
//未完成...