摘要:本文并不逐行地對(duì)源碼進(jìn)行細(xì)致分析,不如說(shuō)是基于以下幾個(gè)問(wèn)題,對(duì)源碼進(jìn)行大致的掃覽。我們已經(jīng)知道,中,允許用戶注冊(cè)監(jiān)聽(tīng)器,這些監(jiān)聽(tīng)器會(huì)在每次執(zhí)行結(jié)束后遍歷觸發(fā)。省略一些無(wú)關(guān)代碼其中,是為了在嵌套的中嵌套執(zhí)行。
react-redux 源碼解讀
[TOC]
前置知識(shí)閱讀本篇文章前,請(qǐng)先確認(rèn)你是否了解以下知識(shí):
react
redux
高階組件
react diff 機(jī)制
其中高階組件如果你不太了解也無(wú)所謂,你只需要知道,高階組件就是一個(gè)工廠函數(shù),它接收一個(gè)組件類(lèi)(或者函數(shù)組件),返回一個(gè)被修改后的新的組件類(lèi)。connect 就是一個(gè)高階組件。
文章內(nèi)會(huì)使用的簡(jiǎn)寫(xiě)
hoc: 高階組件(higher order component)
scu: shouldComponentUpdate
Issues我們知道,react-redux 為開(kāi)發(fā)者提供了 redux 到 react 的 binding。本文并不逐行地對(duì)源碼進(jìn)行細(xì)致分析,不如說(shuō)是基于以下幾個(gè)問(wèn)題,對(duì)源碼進(jìn)行大致的掃覽。
我們把關(guān)注點(diǎn)放在:
connect 是通過(guò)什么方式來(lái)連接 store 的?
怎么分發(fā) state tree 到子組件的?
provider 僅僅只是保持了一個(gè) store 實(shí)例,即使 store 中的 state tree 變化了,由于 react diff 階段只做淺比較,僅比較對(duì)象引用,故 provider.props.store 被視為未發(fā)生變化,那就無(wú)法把新的 state tree 分發(fā)到子組件了。
我們知道 connect 還接收若干配置函數(shù),用來(lái) mapXxToProps ,以及設(shè)置是否進(jìn)行 pure 優(yōu)化等。這些沒(méi)什么意思,我們就不 care 了。
兩個(gè)核心 apireact-redux 只有兩個(gè)核心的部分
Provider
connect
ProviderProvider 的作用僅僅是維護(hù)一個(gè) store 實(shí)例,并使用 context , 為分發(fā) state tree 提供了機(jī)制
connectconnect 顧名思義,連接 container 和 store ,使得 container 能響應(yīng) state tree 的變化。
connect 本身是一個(gè)高階組件,它調(diào)用了 connectAdvanced 這么一個(gè)工廠函數(shù)。
而上面提到的兩個(gè)問(wèn)題,全都由 connectAdvanced 封裝了。
connectAdvancedconnectAdvanced 是一個(gè)高階組件的工廠函數(shù),它返回一個(gè) hoc (高階組件),這個(gè) hoc 最終返回一個(gè) Connect(WrappedComponent) 的組件。
connect 是通過(guò)什么方式來(lái)連接 store 的?在這個(gè) Connect(WrappedComponent) 中,聲明了 getChildContext 函數(shù),通過(guò)它來(lái)獲取到 Provider 中共享的 store 實(shí)例。
NOTE : 理論上,Provider 下任何一個(gè)子組件,只要我們也去聲明了 getChildContext ,那么它就和 connect 了一樣,可以得到 store 實(shí)例了。
connect 怎么分發(fā) state tree 到子組件的?一句話,主要通過(guò) store.subscribe 接口和組件 props 變更自動(dòng) re-render 機(jī)制。
在 react-redux 中,我們定義了這么幾個(gè)東西,幫助我們來(lái)做到上面幾件事情。
selector
subscriptions
每個(gè) Connect(WrappedComponent) 在構(gòu)造函數(shù)中都需要 init 上述兩個(gè)實(shí)體。
selectorselector 主要由 selectorFactory 構(gòu)造,selector 內(nèi)部包含
一個(gè)計(jì)算新 props 的生成函數(shù)
sourceSelector(store.getState(), props)
其中 props 是 selector 之前緩存的,后續(xù)會(huì)直接拿來(lái)和 store.getState() 比較引用
一個(gè) shouldComponentUpdate 的標(biāo)識(shí)
在 Connect(WrappedComponent) 內(nèi)部是直接使用它來(lái)判斷 scu 的
shouldComponentUpdate() { return this.selector.shouldComponentUpdate }
源碼如下
const selector = { // 實(shí)際 run 的邏輯又是在 SelectorFactory 里定義的,這里只是做 scu run: function runComponentSelector(props) { try { const nextProps = sourceSelector(store.getState(), props) // connect 的 scu 實(shí)際邏輯在這里定義了 // 比較 run 之后兩次 props 的引用是否仍然保持相等 if (nextProps !== selector.props || selector.error) { selector.shouldComponentUpdate = true selector.props = nextProps selector.error = null } } catch (error) { selector.shouldComponentUpdate = true selector.error = error } } }
調(diào)用 selector.run 的時(shí)候,主要做了兩件事情
根據(jù)之前緩存的 prevProps 和當(dāng)前 redux store 實(shí)例中的 statet tree 生成新的 props。
通過(guò)比較引用,更新 shouldComponentUpdate 判斷標(biāo)識(shí)
Connect(WrappedComponent) 會(huì)在三處調(diào)用 selector.run:
componentDidMount
componentWillReceiveProps
onStateChanged
之后 React 就會(huì)自動(dòng)向子組件分發(fā)變更后的 props ,實(shí)現(xiàn) re-render。
subcription我們?cè)谏厦嫣岬竭^(guò) Provider 本身是無(wú)法通知 state tree 的變化的,于是為了監(jiān)聽(tīng) state tree 變化,我們需要通過(guò) store.subcribe 接口,來(lái)向 Provider 的 store 實(shí)例注冊(cè)一些監(jiān)聽(tīng)器。
我們已經(jīng)知道,redux 中,store.subcribe 允許用戶注冊(cè)監(jiān)聽(tīng)器,這些監(jiān)聽(tīng)器會(huì)在每次 dispatch 執(zhí)行結(jié)束后遍歷觸發(fā)。
于是在 react-redux 中, Connect(WrappedComponent) 中的 subcription 最終就是被注冊(cè)到 store 中。
initSubscription() { // ...省略一些無(wú)關(guān)代碼 this.subscription = new Subscription(this.store, parentSub, this.onStateChange.bind(this)) }
其中,
parentSub 是為了在嵌套的 connect 中嵌套執(zhí)行 subscription。
new Subscription 主要構(gòu)造了一個(gè)包含 trySubscribe 方法的對(duì)象
trySubscribe() { if (!this.unsubscribe) { this.unsubscribe = this.parentSub ? this.parentSub.addNestedSub(this.onStateChange) : this.store.subscribe(this.onStateChange) this.listeners = createListenerCollection() } }
Connect(WrappedComponent) 在 componentDidMount 時(shí) trySubscribe,在 componentWillUnmount 時(shí) tryUnsubscribe
而 trySubscribe 的主要邏輯就是將 onStateChange 注冊(cè)到 redux.store 中。
而我們已經(jīng)說(shuō)過(guò),onStateChange 主要就是執(zhí)行 selector.run
onStateChange() { // 得到新的 props 和 state this.selector.run(this.props) if (!this.selector.shouldComponentUpdate) { this.notifyNestedSubs() } else { this.componentDidUpdate = this.notifyNestedSubsOnComponentDidUpdate this.setState(dummyState) } }
于是,每次 state tree 發(fā)生變化后,或者更準(zhǔn)確地說(shuō),每次 dispatch 成功后,redux.store 都會(huì)通過(guò)注冊(cè)好的 subscription,執(zhí)行 Connect(WrappedComponent) 中的 onStateChange ,再由 selector.run 來(lái)判斷是否需要生成新的 props。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/87218.html
摘要:帶有內(nèi)部狀態(tài),內(nèi)部可以使用。代表監(jiān)聽(tīng)的全局,也可以說(shuō)是全局的,表示該組件自身攜帶的方法。回答問(wèn)題是通過(guò)應(yīng)用的,將通過(guò)頂層組件傳遞到上下文環(huán)境中。所有頁(yè)面集合緩存不用每次都重新加載通過(guò)綁定用法完參考文章 react-redux把組件分為UI組件和容器組件。先看圖下圖: showImg(https://segmentfault.com/img/bVbkVBz?w=1378&h=1194);...
摘要:介紹概述本次對(duì)源碼的解讀除了傳統(tǒng)的從入手外還將引入帶入問(wèn)題讀源碼的理念,因?yàn)橹挥羞@樣當(dāng)讀完源碼之后才會(huì)有切身的收獲。 介紹 概述 本次對(duì) dva 源碼的解讀除了傳統(tǒng)的從 api 入手外還將引入帶入問(wèn)題讀源碼的理念,因?yàn)橹挥羞@樣當(dāng)讀完源碼之后才會(huì)有切身的收獲。另外除了 dva 的源碼外還會(huì)解讀一些常用的 dva 插件的源碼。 電子書(shū) https://dva-source-docs.net...
摘要:源碼解讀的方法就是給我們提供了靈活的創(chuàng)建符合標(biāo)準(zhǔn)的的方法。用于分解樹(shù),每一個(gè)對(duì)應(yīng)的一個(gè)對(duì)應(yīng)的子。這樣在將傳遞給時(shí)利于分解。源碼實(shí)現(xiàn)了這種將函數(shù)數(shù)組,通過(guò)的方法,實(shí)現(xiàn)層層嵌套的執(zhí)行,達(dá)到中間件的實(shí)現(xiàn)。 Redux 源碼解讀 1.redux-action createAction redux-action的createAction方法就是給我們提供了靈活的創(chuàng)建符合FSA標(biāo)準(zhǔn)的actio...
摘要:更新類(lèi)型及具體內(nèi)容負(fù)責(zé)更新數(shù)據(jù)的具體邏輯。即根據(jù)當(dāng)前及攜帶的信息合成新的數(shù)據(jù)。下面帶著這些問(wèn)題深入了解本質(zhì)上也是高階組件的一種實(shí)現(xiàn)。核心實(shí)現(xiàn)聲明以被子組件獲取。通過(guò)的實(shí)現(xiàn),我們可以得到的重要性淺比較的實(shí)現(xiàn)由此可以看到的重要性。前言 Redux作為通用的狀態(tài)管理器,可以搭配任意界面框架。所以并搭配react使用的話就要借助redux官方提供的React綁定庫(kù)react-redux,以高效靈活的...
摘要:函數(shù)組合,科里化的串聯(lián)結(jié)合示例源碼,實(shí)現(xiàn)也很優(yōu)雅,對(duì)于返回的,將等參數(shù)傳遞進(jìn)去,然后執(zhí)行,等待回調(diào)異步完成再。對(duì)于正常對(duì)象則進(jìn)行下一步。前言 作為前端狀態(tài)管理器,這個(gè)比較跨時(shí)代的工具庫(kù)redux有很多實(shí)現(xiàn)和思想值得我們思考。在深入源碼之前,我們可以相關(guān)注下一些常見(jiàn)問(wèn)題,這樣帶著問(wèn)題去看實(shí)現(xiàn),也能更加清晰的了解。 常見(jiàn)問(wèn)題 大概看了下主要有這么幾個(gè): redux三大原則 這個(gè)可以直接參考...
閱讀 2025·2023-04-26 00:16
閱讀 3475·2021-11-15 11:38
閱讀 3168·2019-08-30 12:50
閱讀 3178·2019-08-29 13:59
閱讀 750·2019-08-29 13:54
閱讀 2496·2019-08-29 13:42
閱讀 3305·2019-08-26 11:45
閱讀 2187·2019-08-26 11:36