国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

少婦白潔系列之React StateUp Pattern, Explained

20171112 / 5515人閱讀

摘要:本文用于闡述模式的算法和數(shù)學(xué)背景,以及解釋了它為什么是里最完美的狀態(tài)管理實(shí)現(xiàn)。歡迎大家討論和發(fā)表意見。

本文用于闡述StateUp模式的算法和數(shù)學(xué)背景,以及解釋了它為什么是React里最完美的狀態(tài)管理實(shí)現(xiàn)。

關(guān)于StateUp模式請(qǐng)參閱:https://segmentfault.com/a/11...

P-State, V-State

如果要做組件的態(tài)封裝,從組件內(nèi)部看,存在兩種不同的state:

p-state, or persistent state, 是生命周期超過組件本身的state,即使組件從DOM上銷毀,這些state仍然需要在組件外部持久化;

v-state, or volatile state, 是生命周期和組件一樣的state,如果組件從DOM上銷毀,這些state一起銷毀;

根據(jù)這個(gè)定義,React組件的this.state毫無疑問是v-state;

開發(fā)者常說的model或者store state應(yīng)該看作p-state,但是這樣說過于籠統(tǒng)和寬泛,沒有邊界;而另一個(gè)說法,view state,同樣缺乏明確的邊界定義;所以我們暫時(shí)避免使用這兩種表述;用具有嚴(yán)格定義的p-statev-state來展開討論;

責(zé)任與邊界

對(duì)象封裝的責(zé)任與邊界在面向?qū)ο缶幊汤锒际翘貏e基礎(chǔ)的概念,良好的模塊封裝必須做到責(zé)任明確和邊界清晰;每個(gè)類型的對(duì)象有明確的責(zé)任和邊界定義,不同類型的對(duì)象之間通過組合、接口調(diào)用、或者消息機(jī)制完成交互,構(gòu)成易于維護(hù)的系統(tǒng);

但是在React里,這個(gè)設(shè)計(jì)方式變得難以付諸實(shí)施;

React的機(jī)制是父組件不該直接訪問子組件,因?yàn)樽咏M件的生命周期不是父組件維護(hù)的,是React維護(hù)的;React父組件不去訪問子組件也意味著子組件需要的狀態(tài)要提升至父組件維護(hù),父組件更新了這些狀態(tài)之后,通過props向下傳遞;

觸發(fā)狀態(tài)改變的原因可以由子組件發(fā)起(看起來更像封裝),但是需要父組件提供Callback,邏輯處理仍然由父組件完成;這意味著子組件的狀態(tài)和行為,都托管到父組件去了,子組件只負(fù)責(zé)渲染和解釋用戶輸入行為;但這給封裝和重用制造了麻煩,相同的邏輯會(huì)重復(fù)書寫在不同的父組件中;

StateUp模式中,我們明確給出了p-state的定義和實(shí)現(xiàn),即StateUp組件中的靜態(tài)State類,用于構(gòu)造p-state對(duì)象;

StateUp組件的渲染函數(shù)相當(dāng)于f(p-state, v-state, props);

增加的p-state對(duì)象用于維護(hù)原本要提升至React父組件的狀態(tài),以及行為;換句話說,如果使用p-state對(duì)象,原本由子組件托管到父組件維護(hù)的(屬于子組件維護(hù)責(zé)任的)狀態(tài),及其導(dǎo)致的通過props向下傳遞的數(shù)據(jù),應(yīng)該移動(dòng)到p-state內(nèi)維護(hù),組件直接通過this.props.state訪問;

當(dāng)然這不能消除一個(gè)StateUp組件渲染需要的所有props,由于HTML/DOM的結(jié)構(gòu)設(shè)計(jì),完整渲染組件需要的數(shù)據(jù)注定是它的所有父組件容器向下傳遞的數(shù)據(jù)的總和的一部分(即需要用到的部分)。

P-State的維護(hù)

p-state的實(shí)現(xiàn)在StateUp模式中有詳細(xì)介紹,這里不贅述;這里先闡述一下基于p-statev-state概念,StateUp模式中的生命周期問題如何嚴(yán)格表述,然后闡述StateUp模式的數(shù)學(xué)本質(zhì);

StateUp模式中,StateUp組件A的p-state不在組件A中維護(hù),它需要提升至父組件B,提升有可能是遞歸的,即在父組件B中被繼續(xù)提升;直到某一個(gè)React組件C,把這個(gè)樹狀層級(jí)的p-state對(duì)象放置在自己的v-state (this.state)中,這意味著StateUp組件A的狀態(tài)生命周期,和組件C的視圖生命周期是一致的;

我們把組件C稱為組件A的p-state ancestor;

組件C在它的任何子組件的p-state發(fā)生變化時(shí),都會(huì)調(diào)用this.setState更新自己的v-state,對(duì)于React而言,這觸發(fā)所有子組件的渲染;但由于immutable的數(shù)據(jù)結(jié)構(gòu)和PureComponent的SCU設(shè)計(jì),render是按需的,僅需要render的子組件會(huì)被render;

p-state的更新路徑

StateUp模式中有一些一眼看上似乎不合理的設(shè)計(jì);

const StateUp = base => class extends base {

  setSubState(name, nextSubState) {
    let state = this.props.state || this.state
    let subState = state[name]
    let nextSubStateMerged = Object.assign(new subState.constructor(), subState, nextSubState)
    let nextState = { [name]: nextSubStateMerged }
    this.props.setState
      ? this.props.setState(nextState)
      : this.setState(nextState)
  }

  setSubStateBound(name) {
    let obj = this.setSubStateBoundObj || (this.setSubStateBoundObj = {})
    return obj[name] 
      ? obj[name] 
      : (obj[name] = this.setSubState.bind(this, name))
  }

  stateBinding(name) {
    return {
      state: this.props.state ? this.props.state[name] : this.state[name],
      setState: this.setSubStateBound(name)
    }
  }
}

既然我們明確分清了p-statev-state,為什么p-state的更新,要象上述代碼一樣走React組件的方法,為什么不是把p-state對(duì)象多帶帶構(gòu)建一個(gè)tree,畢竟它是JavaScript對(duì)象,寫起來并不難;

這個(gè)問題的本質(zhì)涉及到了immutable的tree數(shù)據(jù)結(jié)構(gòu)的一個(gè)常見問題,即你不可能構(gòu)建一個(gè)cyclic數(shù)據(jù)結(jié)構(gòu)是immutable的,至少在JavaScript這種有statement沒有l(wèi)azy evaluation的語言里不可能;

事實(shí)上我為這個(gè)想法寫了代碼,例如在父組件的p-state對(duì)象中這樣寫:

// parent component p-state object
static State = class State {
  constructor() {
    this.sub1 = new Sub.State()
    this.sub1.parent = this
    this.sub1.propName = "sub1"
  }
}

這樣就在子組件的p-state內(nèi)裝載了父組件的p-state的引用;看起來在子組件的p-state上似乎可以設(shè)計(jì)一個(gè)setState方法(不是React Component上的setState),直接調(diào)用父組件的p-state對(duì)象上的setState方法,就可以實(shí)現(xiàn)遞歸更新;

但這是一個(gè)假象;考慮如下A/B/C/D的結(jié)構(gòu):

A      ->    A"
  B            B"
    C            C"
    D            D

在C更新至C"時(shí),D沒有變化,但是D的父對(duì)象不再是B而是B";

解決這個(gè)問題的辦法,也是通用的immutable tree數(shù)據(jù)結(jié)構(gòu)的雙向引用問題的解法,是所謂的Red-Green Tree (參見參考文獻(xiàn))。

Red Green Tree

Red-Green Tree在外部看是一個(gè)Tree,在內(nèi)部分成Red Tree和Green Tree,外部訪問通過Red Tree,Green Tree是內(nèi)部的;

Red Tree的結(jié)構(gòu)和Green Tree一模一樣,它是一個(gè)mutable tree,每個(gè)節(jié)點(diǎn)包含自下至上的引用(parent引用)和向右引用Green Tree上的對(duì)應(yīng)對(duì)象,Green Tree是immutable tree,只有自上至下的引用:

red tree            green tree
A -> null, A"        A"
  B -> A, B"           B"
    C -> B, C"           C"
    D -> B, D"           D"
    
A -> null, A"        A"
  B -> A, B"           B"
    C -> B, C"           C"
    D -> B, D"           D"

當(dāng)操作C的時(shí)候,Green Tree的A"/B"/C"都會(huì)發(fā)生變化,同時(shí)Red Tree自上至下更新,它的向上引用不變,但是向右的引用全部刷新成最新的Green Tree對(duì)象;這樣既維護(hù)了雙向引用,又實(shí)現(xiàn)了immutable;

StateUp模式中,Component相當(dāng)于Red Tree上的節(jié)點(diǎn),p-state對(duì)象是Green Tree上的節(jié)點(diǎn);Component的this.prop.state相當(dāng)于向右引用,render時(shí)自上至下更新(B" -> B");this.prop.setState相當(dāng)于向上引用(B->A),它是穩(wěn)定的,這個(gè)穩(wěn)定引用保證在更新D時(shí)可以先找到父節(jié)點(diǎn)B然后找到最新的B",從而正確實(shí)現(xiàn)D在父對(duì)象里的引用更新;

由于React自上至下渲染,所以在父組件內(nèi)拿子組件的引用是危險(xiǎn)的,因?yàn)榭赡苓^期;但是子組件向父組件的引用在每次渲染之后都是保證正確的;

所以在StateUp模式中,通過用Component承擔(dān)Red Tree的責(zé)任,保證p-state tree可以實(shí)現(xiàn)immutable的Green Tree,有此帶來p-state對(duì)象的高可維護(hù)性和性能保證;

我曾經(jīng)認(rèn)為stateBinding函數(shù)實(shí)現(xiàn)了兩個(gè)prop傳遞是不太合理的設(shè)計(jì),但從上面的圖示看這非常合理,其中state是子組件的向右引用,setState是子組件的向上引用,利用React的props和render機(jī)制實(shí)現(xiàn)Red-Green Tree的更新,這是React和Immutable的完美結(jié)合。

狀態(tài)管理

如果去對(duì)比其他的React狀態(tài)管理器,使用這里給出的p-statev-state概念,會(huì)發(fā)現(xiàn):

大多數(shù)狀態(tài)管理器把p-state提升到最頂層,構(gòu)建外部狀態(tài)樹;

狀態(tài)管理器需要用戶手工代碼來實(shí)現(xiàn)組件更新綁定,以提高效率,但這是理論上的美好,實(shí)際上程序員不會(huì)對(duì)更新做太細(xì)粒度的管理,除非遇到嚴(yán)重性能問題;

各種狀態(tài)管理器都在試圖利用immutable來做性能優(yōu)化,但是沒有觸及問題的本質(zhì),即Red-Green Tree問題,這也是React的本質(zhì);如果你僅僅使用全局狀態(tài)樹,你只做對(duì)了問題的一半。

相信每個(gè)深入思考過React的外部狀態(tài)樹和組件樹關(guān)系的程序員都曾經(jīng)在大腦中有過這樣的問題,它們兩個(gè)到底該不該一致?

StateUp模式給這個(gè)問題一個(gè)明確的回答:應(yīng)該,但不是在React組件層面上的,而是StateUp組件層面的;更確切的說是p-state ancestor組件構(gòu)成的樹,就是Model的結(jié)構(gòu)樹,它包含運(yùn)行時(shí)組件狀態(tài)組合結(jié)構(gòu)和生命周期兩方面的定義;而每個(gè)節(jié)點(diǎn)拓?fù)湔归_的React Component子樹,僅具有視圖層的含義;

所以在設(shè)計(jì)時(shí)仔細(xì)考慮p-state ancestor的處理,是對(duì)狀態(tài)該寫在哪里的最有幫助的思考;同時(shí),基于StateUp模式,這個(gè)Model的結(jié)構(gòu)是自動(dòng)組出來的,不是開發(fā)者獨(dú)立定義的;

React的this.state僅針對(duì)v-state設(shè)計(jì),在沒有p-state對(duì)象封裝的情況下,它相當(dāng)于把p-state ancestor的子樹展開后,內(nèi)部所有形式無態(tài)但本該有態(tài)的組件的態(tài)和行為都提升到該組件內(nèi)實(shí)現(xiàn),為代碼重用和維護(hù)帶來很大麻煩;

從前面Red-Green Tree的分析可以看出,提取p-state進(jìn)行對(duì)象封裝,不但是可行的,而且是恰當(dāng)?shù)模梢杂行Ю肞ureComponent特性提高最高渲染效率,在模型上也有數(shù)學(xué)算法的支撐。

因?yàn)楣ぷ鞣泵ξ覠o意把StateUp模式搞成象redux那樣的流行項(xiàng)目,代碼量也撐不起一個(gè)項(xiàng)目的規(guī)模;而且StateUp的代碼本身也還顯得過于簡(jiǎn)陋,也許讓p-state對(duì)象能夠emit event可以創(chuàng)造更多的便利,等等;

但是在工程實(shí)踐上我會(huì)積極實(shí)踐這種方式,遇到實(shí)際問題也會(huì)盡最大努力去在這個(gè)框架下尋求解決方案,畢竟在目前階段看起來,StateUp模式把UI的開發(fā)帶回了我們熟悉的面向?qū)ο箢I(lǐng)域,對(duì)各種復(fù)雜的行為模式和結(jié)構(gòu)模式,都有大量的成熟模式可用,而不必在非常割裂的組件交互機(jī)制下感覺捉襟見肘。

最后

這20行代碼是我一年多的React開發(fā)實(shí)踐中寫過的最好的代碼,它很粗糙,但是它背后的算法模型有異常簡(jiǎn)單強(qiáng)大的力量;

它并不是基于Red-Green Tree推演的結(jié)果,而是偶得后對(duì)其做更深層面的思考,發(fā)現(xiàn)它完全契合了immutable數(shù)據(jù)結(jié)構(gòu)和函數(shù)式編程的設(shè)計(jì)思想;而immutable,是我們目前已知雖然性能并非最佳,但是解決自動(dòng)刷新問題的最簡(jiǎn)單手段;同時(shí)函數(shù)式編程的易于調(diào)試也是巨大的工程收益。

歡迎大家討論和發(fā)表意見。

參考文獻(xiàn)

REF 1: https://blogs.msdn.microsoft....

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/81957.html

相關(guān)文章

  • 少婦白潔系列React StateUp模式

    摘要:一般這種情況會(huì)在類的構(gòu)造函數(shù)內(nèi)創(chuàng)建一個(gè)屬性,引用或詞法域的,但后面會(huì)看到我們有更好的辦法,避免這種手工代碼。 換句話說,StateUp模式把面向?qū)ο蟮脑O(shè)計(jì)方法應(yīng)用到了狀態(tài)對(duì)象的管理上,在遵循React的組件化機(jī)制和基于props實(shí)現(xiàn)組件通訊方式的前提之下做到了這一點(diǎn)。 ---- 少婦白潔 閱讀本文之前,請(qǐng)確定你讀過React的官方文檔中關(guān)于Lifting State Up的論述: ht...

    jaysun 評(píng)論0 收藏0
  • 少婦白潔如何使用React 001?

    摘要:目的是為了解決在重用的時(shí)候,持久和方法重用的問題。換句話說你不用擔(dān)心把組件寫成模式不好重用,如果你需要傳統(tǒng)的方式使用,一下即可。 這篇文章所述的思想最終進(jìn)化成了一個(gè)簡(jiǎn)單的狀態(tài)管理模式,稱React StateUp Pattern,詳細(xì)介紹請(qǐng)參閱:https://segmentfault.com/a/11... 寫了一個(gè)非常簡(jiǎn)單的實(shí)驗(yàn)性Pattern,暫且稱為PurifiedCompon...

    davidac 評(píng)論0 收藏0
  • React 可視化開發(fā)工具 shadow-widget 最佳實(shí)踐(上)

    摘要:上例的功能塊定義了如下節(jié)點(diǎn)樹入口節(jié)點(diǎn)是面板,結(jié)合該節(jié)點(diǎn)的函數(shù)書寫特點(diǎn),我們接著介紹最佳實(shí)踐如何處理功能塊之內(nèi)的編程。 本文介紹 React + Shadow Widget 應(yīng)用于通用 GUI 開發(fā)的最佳實(shí)踐,只聚焦于典型場(chǎng)景下最優(yōu)開發(fā)方法。分上、下兩篇講解,上篇概述最佳實(shí)踐,介紹功能塊劃分。 showImg(https://segmentfault.com/img/bVWu3d?w=6...

    techstay 評(píng)論0 收藏0
  • 少婦白潔一起學(xué)JavaScriptAsync/Await II

    摘要:的科學(xué)定義是或者,它的標(biāo)志性原語是。能解決一類對(duì)語言的實(shí)現(xiàn)來說特別無力的狀態(tài)機(jī)模型流程即狀態(tài)。容易實(shí)現(xiàn)是需要和的一個(gè)重要原因。 前面寫了一篇,寫的很粗,這篇講講一些細(xì)節(jié)。實(shí)際上Fiber/Coroutine vs Async/Await之爭(zhēng)不是一個(gè)簡(jiǎn)單的continuation如何實(shí)現(xiàn)的問題,而是兩個(gè)完全不同的problem和solution domain。 Event Model 我...

    番茄西紅柿 評(píng)論0 收藏0
  • 少婦白潔一起學(xué)JavaScriptAsync/Await

    摘要:匿名函數(shù)是我們喜歡的一個(gè)重要原因,也是,它們分別消除了很多代碼細(xì)節(jié)上需要命名變量名或函數(shù)名的需要。這個(gè)匿名函數(shù)內(nèi),有更多的操作,根據(jù)的結(jié)果針對(duì)目錄和文件做了不同處理,而且有遞歸。 能和微博上的 @響馬 (fibjs作者)掰扯這個(gè)問題是我的榮幸。 事情緣起于知乎上的一個(gè)熱貼,諸神都發(fā)表了意見: https://www.zhihu.com/questio... 這一篇不是要說明白什么是as...

    Bryan 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<