成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

React 可視化開發(fā)工具 Shadow Widget 非正經(jīng)入門(之四:flux、mvc、mvvm

msup / 1751人閱讀

摘要:是分發(fā)器,是數(shù)據(jù)與邏輯處理器,會(huì)在注冊(cè)針對(duì)各個(gè)命令字的響應(yīng)回調(diào)函數(shù)。當(dāng)按如下方式觸發(fā)回調(diào)時(shí),回調(diào)函數(shù)具備事件的特性。

本系列博文從 Shadow Widget 作者的視角,解釋該框架的設(shè)計(jì)要點(diǎn)。本篇解釋 Shadow Widget 在 MVC、MVVM、Flux 框架之間如何做選擇。

1. React Flux 框架

Facebook 官方為 React 提出了 flux 框架,也自己實(shí)現(xiàn)了一個(gè) flux.js,盡管這個(gè)庫(kù)設(shè)計(jì)得很差勁,但所有第三方為 React 開發(fā)的單向數(shù)據(jù)流方案,起點(diǎn)都是該庫(kù)官方所提的 Flux concepts,下面是經(jīng)典結(jié)構(gòu)圖:

Action 可簡(jiǎn)單理解為指令(或命令),由命令字 type 與命令參數(shù) data(或稱 payload)組成。Dispatcher 是分發(fā)器,Store 是數(shù)據(jù)與邏輯處理器,Store 會(huì)在 Dispatcher 注冊(cè)針對(duì)各個(gè)命令字的響應(yīng)回調(diào)函數(shù)。View 就是 React Component,View 常使用 Store 中的數(shù)據(jù)并訂閱 Store 發(fā)生變化來(lái)刷新自身顯示。

幾個(gè)部件之間數(shù)據(jù)單向流動(dòng),如下:

  Action -> Dispatcher -> Store -> View

形成單向流動(dòng)的原理較簡(jiǎn)單,大致這樣,Store 在 Dispatch 注冊(cè)的回調(diào)函數(shù),由 Action 觸發(fā),Dispatcher 解析命令字,找出相應(yīng)回調(diào)用函數(shù)實(shí)現(xiàn)調(diào)用即可。當(dāng) Dispatcher 按如下方式觸發(fā)回調(diào)時(shí),回調(diào)函數(shù)具備事件的特性。

  setTimeout( function() {
    callback();
  },0);

如果立即調(diào)用 callback,那只是回調(diào),如果延時(shí) 0 秒會(huì)讓 callback 在下個(gè)周期被調(diào)用,就成事件了,單向數(shù)據(jù)流因此得到保證。

當(dāng)然,上面介紹非常簡(jiǎn)略,把核心機(jī)制講明白,reflux、redux 讓注冊(cè)回調(diào)變事件也都用這個(gè)機(jī)制。當(dāng)然,事件化回調(diào)的處理過(guò)程可能很復(fù)雜,比如 Dispatcher 還提供 waitFor() 等待一項(xiàng)或多項(xiàng) Action 的接口,我們略去不細(xì)講。

2. React 中的 MVC

React 實(shí)現(xiàn)的虛擬 DOM 部分(即核心庫(kù) react.jsreact-dom.js)是 MVC 中的 "V",其 MVC 框架圖如下:

當(dāng)你只使用 React 的核心庫(kù),未使用 reflux、redux 等單向數(shù)據(jù)流機(jī)制時(shí),所用的 MVC 就是上圖樣子。如何構(gòu)造 Controller 與 Model 是自由的,甚至你想將它改造成 MVVM 也是自由的,畢竟 React 的核心庫(kù)只提供虛擬 DOM 映射,與 HTML 原生的 DOM 一起提供 "View"。后面我們真的要介紹怎么改成 MVVM。

Flux、MVC、MVVM 這三者是對(duì)等的架構(gòu),我們不能直接將 Flux 框架往 MVC 上套。

3. 復(fù)雜環(huán)境對(duì) MVC 框架的影響

在 React 中使用 MVC 主要缺陷是:當(dāng)應(yīng)用規(guī)模變大,M, V, C 之間依賴關(guān)系會(huì)變復(fù)雜。下圖還不算太復(fù)雜,只用到 2 個(gè) Module。

React 虛擬 DOM 對(duì)真實(shí) DOM 做了一次抽像,附加 props、state 等概念,再加上異步時(shí)序干擾,原先還勉強(qiáng)玩得轉(zhuǎn)的 MVC,已變得很不好用,開發(fā)、調(diào)試、定位問(wèn)題都變困難了。

引入 Flux 能有針對(duì)性的緩解上述困難。其一,用單數(shù)據(jù)流向串接各 View,讓與 Model 交互的那個(gè) View(也稱 Controller View)承擔(dān)設(shè)計(jì)復(fù)雜性,其它 View 只做簡(jiǎn)單工作,如展示界面、簡(jiǎn)單響應(yīng)鼠標(biāo)點(diǎn)擊等操作。

其二,用 Action 與 Dispatcher 簡(jiǎn)化 Controller,不弄那么多 Controller,歸總到一個(gè) Dispatcher。其三,采用 Functional Reactive Programming 方法構(gòu)造響應(yīng)式的單向數(shù)據(jù)流機(jī)制,以此應(yīng)對(duì)異步時(shí)序問(wèn)題。

React 生態(tài)鏈中有多種 Flux 實(shí)現(xiàn),他們本質(zhì)一樣,表面差別不算大,通常幾句話就能概括。reflux 采用多 store 方案,把用于集中分發(fā)的 Dispatcher 簡(jiǎn)化掉了,redux 采用單 store 方案,把分發(fā) Action 后的處理分解給眾多 Reducer 函數(shù),也就是說(shuō),上圖多個(gè) Store 的功能,用 "單 Store + 眾多 Reducer 函數(shù)" 替換。

4. Shadow Widget 與 Redux 走在兩個(gè)方向上

Redux 最大優(yōu)點(diǎn)是實(shí)施徹底函數(shù)式編程,最大缺點(diǎn)也是徹底函數(shù)式。它本身并未簡(jiǎn)化設(shè)計(jì)復(fù)雜性,只是轉(zhuǎn)移復(fù)雜性,但按官方原生的 Flux 概念,我們是按對(duì)象方式理解一個(gè)個(gè) Store 的,在設(shè)計(jì)時(shí),處理 Store 與 View,以及與 Action 之間關(guān)系時(shí),都按對(duì)象方式去思考的,現(xiàn)在把復(fù)雜性轉(zhuǎn)移到眾多 reducer 函數(shù)上,函數(shù)式思維不利于設(shè)計(jì)分解(相對(duì)對(duì)象化思維而言)。

Redux 之所以能盛行,與 React 自身限制有關(guān)。React 的虛擬 DOM 樹限制數(shù)據(jù)單向(向下)傳遞,跨節(jié)點(diǎn)讀取屬性極不方便,如果我們把所有服務(wù)于 render 的 state 數(shù)據(jù),獨(dú)立到節(jié)點(diǎn)之外的全局函數(shù)(reducer)中去組裝呢?所有用到的 state 串一起,形成一個(gè)大的全局變量(就是單 Store),reducer 函數(shù)想怎么讀就怎么讀。這個(gè)方案以大幅度函數(shù)式改造為代價(jià),來(lái)突破 React 的限制。

Shadow Widget 做的正相反,嘗試維持對(duì)象化思維習(xí)慣,把 Store 與 ViewModel 合一(后面還有詳細(xì)說(shuō)明)以便減輕思考負(fù)擔(dān);通過(guò)建立 Widget 樹,用 this.componentOf() 快速檢索相關(guān)節(jié)點(diǎn),以求方便的存取屬性;再設(shè)計(jì) duals 雙源屬性,建立一套能自動(dòng)識(shí)別數(shù)據(jù)變化,并驅(qū)動(dòng)單向數(shù)據(jù)流的機(jī)制。

5. Controller View 數(shù)據(jù)傳遞

我們研究一下 Controller View 與 Store 對(duì)接及與下級(jí) View 的連接關(guān)系,取上圖局部,放大講解,如下:

當(dāng) Store 中有數(shù)據(jù)更新,通知 Controller View 更新界面,Controller View 就從 Store 讀得 state 數(shù)據(jù),來(lái)更新自己的 state。而自身 state 變化將觸發(fā)下級(jí) View 聯(lián)動(dòng)更新,變化的信息在各子級(jí)借助 props 屬性實(shí)現(xiàn)傳遞。

為下文講解作準(zhǔn)備,這里我們先拎一拎 Store 該具備的特性:

要提供事件通知功能,當(dāng) Store 中的 state 數(shù)據(jù)有變化,通知 Controller View 刷新界面。

對(duì) Controller View 暴露 state 數(shù)據(jù),有兩種設(shè)計(jì)可選,一是讓事件通知中帶 state 數(shù)據(jù),二是事件通知不帶數(shù)據(jù),要由 Controller View 主動(dòng)到 Store 查詢。結(jié)合 FRP 編程特點(diǎn),第二個(gè)設(shè)計(jì)更好,如果數(shù)據(jù)連續(xù)多次更新,從 Store 讀數(shù)據(jù)應(yīng)合并為一次,取最新值。

何時(shí)通知 Controller View 刷新可能比較復(fù)雜,涉及條件組合,比如要 Action A 與 Action B 都發(fā)生后,才能觸發(fā)事件通知。

6. 向 MVVM 演化

我們換一個(gè)角度看 flux 框架,傳遞 Action 相當(dāng)于 "emit ",將它弱化考慮,另外,Dispatcher 也可弱化,reflux 相比官方的 React flux,一個(gè)重要改進(jìn)就是去掉 Dispatcher,工具復(fù)雜性因此降了不少。

這么弱化、簡(jiǎn)化后,F(xiàn)lux 框架就剩 Store 與 View,參照 MVC 框架,這里 Store 與 MVC 中 Model 是對(duì)應(yīng)的,某種程度上說(shuō),F(xiàn)lux 概念與 MVC 具備一定兼容性。

reflux 的 Store 仿 React Component 設(shè)計(jì) API,學(xué)習(xí)成本進(jìn)一步降低,遺憾的是它是多 Store 結(jié)構(gòu),一個(gè) Store 對(duì)應(yīng)一個(gè) View(有時(shí)對(duì)應(yīng)多個(gè)),Store 變多后容易讓開發(fā)者感到困惑,許多屬性設(shè)計(jì)一時(shí)想不清楚該放在 Store,還是放在 View,經(jīng)常換來(lái)?yè)Q去。這里我沒說(shuō)多 Store 設(shè)計(jì)不對(duì),單 Store 有單 Store 的問(wèn)題。而是,多 Store 與 多 View 之間如何思考定位有點(diǎn)擰巴,不像 MVVM 那么直接。

MVVM 采用雙向綁定,View 的變動(dòng)自動(dòng)反映到 ViewModel,這是非常簡(jiǎn)單易用的方式,MVVM 在人性化方面比前端其它框架好出很多,因?yàn)樵O(shè)計(jì)一項(xiàng)功能,開發(fā)者首先想的是界面怎么體現(xiàn),加個(gè)按鈕,還是加個(gè)輸入框,然后圍繞著按鈕或輸入框,思考有什么動(dòng)作,比如,點(diǎn)擊按鈕后下一步做什么。換成 Flux 思考方式,Store 與 View 之間如何交互要多思考一次,還不以 "界面該怎么呈現(xiàn)" 為思考原點(diǎn),因?yàn)?Action 與 Dispatch 的設(shè)計(jì)促使你先考慮 Store 的數(shù)據(jù)結(jié)構(gòu)。

如果讓 MVVM 再支持 "所見即所得" 的可視化設(shè)計(jì),它的易用性將拉開 Flux 更遠(yuǎn),加上 Flux 天然的函數(shù)式編程傾向,疊加 react-router 等工具,也自然以路由指令、Action命令、狀態(tài)數(shù)據(jù)為思考出發(fā)點(diǎn)。比如 react-router 強(qiáng)調(diào),以 "路由" 如何設(shè)置為功能開發(fā)的第一出發(fā)點(diǎn),不像 MVVM 是以交互界面設(shè)計(jì)為第一出發(fā)點(diǎn)。所以,說(shuō)句實(shí)話,React 生態(tài)鏈上的工具比 Vue 難用得多,這也是 React 急需 Shadow Widget 之類工具的理由。

現(xiàn)在我們明確了引入 MVVM 的收益,非常值得做。問(wèn)題關(guān)鍵是,它如何與 Flux 共存?

首先,F(xiàn)lux 中的 Store 與 Controller View 可以合并,大膽一點(diǎn),肯定不會(huì)死人。以 reflux 現(xiàn)有設(shè)計(jì)為例,如果一個(gè) React Component 節(jié)點(diǎn)不顯示到界面,比如

其中,雙合一 "Store + Controller View""VM""VM + V",視該 React Component 需不需在界面顯示而定,若同時(shí)還用作界面元素的就是 "VM + V"。

Flux 要求的 Action 與 Dispatcher 已被各節(jié)點(diǎn)的 duals.attr 屬性代替,其中屬性名(attr) 與 Action 的命令字(type)對(duì)等,屬性值與 Action 的數(shù)據(jù)(Payload)對(duì)等。各個(gè) duals.attr 可被自身節(jié)點(diǎn)或其它節(jié)點(diǎn)偵聽,當(dāng) duals.attr 取值變化時(shí),相應(yīng)的偵聽函數(shù)會(huì)按事件方式自動(dòng)被回調(diào)。

至于 Model,它最簡(jiǎn)的形態(tài)就是各 View 節(jié)點(diǎn)的 duals.xxx 屬性。遇到復(fù)雜的,不妨定義專職的數(shù)據(jù)服務(wù),用不顯示界面的 Controller View 來(lái)定義,如上所述,這是 "VM"。但當(dāng)它只處理 duals.attr 數(shù)據(jù),沒有其它功能時(shí),"VM" 的角色將退化為 "M"。比如 ajax 數(shù)據(jù)服務(wù)(用于從服務(wù)側(cè)請(qǐng)求數(shù)據(jù),往服務(wù)側(cè)保存數(shù)據(jù)),完全可以用 style.display="none"

節(jié)點(diǎn)來(lái)構(gòu)造,它以 duals.attr1, duals.attr2 等接口對(duì)外提供數(shù)據(jù)的讀、寫、偵聽等服務(wù)。

值得一提的是:Shadow Widget 的 MVVM 與 Flux 框架是兼容的,與 Functional Reactive Programming 編程也是兼容的。上圖按 Flux 方式繪圖,若要體現(xiàn) MVVM,這么繪制:

上圖中,區(qū)分 View 與 ViewModel 的主要依據(jù)是:一個(gè) Component 節(jié)點(diǎn)是否納入編程,若納入編程(定義投影定義,或 idSetter 函數(shù))應(yīng)視作 ViewModel,否則應(yīng)視作 View,即使這個(gè) View 使用一些 trigger, $for, $if 等控制指令也如此。

7. 對(duì)照 Vue 的 MVVM 舉個(gè)例子

一個(gè) Vue 的 MVVM 例子如下。

對(duì)應(yīng)于 Shadow Widget,界面 View 定義如下:

添加

VM 定義如下:

idSetter["btn_todo"] = function(value,oldValue) {
  if (value <= 2) {
    if (value == 1) {  // init process
      this.setEvent( {
        $onClick: function(event) {
          var inputComp = this.componentOf("http://input");
          var text = inputComp.duals.value.trim();
          if (text) {
            var dataComp = this.componentOf(0);
            dataComp.duals.data = ex.update(dataComp.duals.data, {
              $push:[{text:text}],
            });
            inputComp.duals.value = "";
          }
        },
      });
    }
    return;
  }
};

Shadow Widget 的 MVVM 與 Vue 相比,更突出從 "界面布局" 出發(fā)思考設(shè)計(jì),更傾向于函數(shù)式編程風(fēng)格。比如:

在一個(gè) VM 中,Shadow Widget 將 Model 分散在各層多個(gè) React Componet 中,數(shù)據(jù)服務(wù)以 duals.xxx 方式提供。而 Vue 集中在一處定義數(shù)據(jù)。
Shadow Widget 先考慮界面如何設(shè)計(jì),確定界面元素后,再考慮相關(guān)數(shù)據(jù)綁捆到哪個(gè)節(jié)點(diǎn)更方便,所以數(shù)據(jù)服務(wù)是分散的,Vue 則提前考慮數(shù)據(jù)結(jié)構(gòu)如何設(shè)計(jì),要集中。所以,這個(gè)例子中,用 Vue 時(shí) data.newTodo 定義到 Model,用 Shadow Widget 則視作一個(gè)過(guò)程數(shù)據(jù),不必在對(duì)外接口體現(xiàn)。

數(shù)據(jù)分散,處理函數(shù)也分散定義,所以上面 Shadow Widget 的事件函數(shù),要用 this.componentOf() 動(dòng)態(tài)查找相關(guān)節(jié)點(diǎn)。Vue 集中定義數(shù)據(jù),與數(shù)據(jù)相關(guān)的節(jié)點(diǎn)、動(dòng)作、事件等函數(shù)也隨之被鎖定。這兩種方式各有利弊,Vue 方式簡(jiǎn)單明了,Shadow Widget 更動(dòng)態(tài)、更函數(shù)式,使用要復(fù)雜些,但應(yīng)付各種變化自由些,功能更強(qiáng)些,比如各層節(jié)點(diǎn)動(dòng)態(tài)增刪、改換。

8. 函數(shù)如何作為數(shù)據(jù)進(jìn)行傳遞

Shadow Widget 要支持界面可視化設(shè)計(jì),可視設(shè)計(jì)的產(chǎn)出是界面元素的疊加物,當(dāng)這種疊加物含有函數(shù)定義時(shí),保存設(shè)計(jì)成果,或緩存設(shè)計(jì)結(jié)果(用于 undo 與 redo)將很成問(wèn)題。因?yàn)楹瘮?shù)定義要附帶上下文才有意義,另外,函數(shù)定義體(即 JS 腳本)可以是任意字符,混在界面定義中,給結(jié)構(gòu)化的解析設(shè)計(jì)結(jié)果也帶來(lái)挑戰(zhàn)。所以,Shadow Widget 限制可視設(shè)計(jì)過(guò)程中使用函數(shù)化數(shù)據(jù),設(shè)計(jì)態(tài)的 props 數(shù)據(jù)傳遞不能有函數(shù)對(duì)象。

在 Shadow Widget 中,與 JSX 對(duì)等的界面數(shù)據(jù)化描述格式叫 json-x,因?yàn)?JSON 數(shù)據(jù)不能帶 function 定義,在數(shù)據(jù)的序列化方面與 JSON 接近,所以就叫 json-x 格式了。界面的可視化設(shè)計(jì)過(guò)程中,輸出的(或緩存的),就是這個(gè)基于 json-x 的數(shù)據(jù)。

Shadow Widget 借助在 main[widget_path] 預(yù)登記投影類定義,實(shí)現(xiàn) function 的動(dòng)態(tài)捆綁,還借助 idSetter[id_string] 預(yù)登記 idSetter 函數(shù),這兩者讓界面可視化設(shè)計(jì)時(shí)避開了函數(shù)對(duì)象的傳遞,設(shè)計(jì)態(tài)下投影定義與 idSetter 函數(shù)不被捆綁。

不過(guò)在設(shè)計(jì)態(tài),某些第三方庫(kù)需要讓特定構(gòu)件捆綁函數(shù)對(duì)象,比如封裝 slides.js 形成直方圖、餅圖等樣板,在可視化設(shè)計(jì)中,捆綁的函數(shù)就要啟用,否則可視化交互設(shè)計(jì)中直方圖、餅圖等不被繪制。

Shadow Widget 為這類需求提供兩種解決方案。其一,使用 初始化列表(注意,不是 W.$onLoad),該列表中的初始化函數(shù)在設(shè)計(jì)態(tài)也被調(diào)用,通常用它注冊(cè)特定廠商的庫(kù)化 UI 節(jié)點(diǎn)。庫(kù)化 UI 供設(shè)計(jì)中引用,它自身不介入中間設(shè)計(jì)成果的保存或緩存,在 $$onLoad 初始化函數(shù)中可捆綁投影類,或傳遞 idSetter 函數(shù)。

其二,類似 T.rewgt.DelayTimer 注冊(cè)一個(gè)自行開發(fā)的 WTC 類,然后界面的轉(zhuǎn)義標(biāo)簽就可以用

引用它。

9. 總結(jié)

我一直認(rèn)為,開發(fā)語(yǔ)言、編程框架只是人類思維的輔助表達(dá)器,人腦觀照世界,見山是山,見水是水,人要一個(gè)個(gè)去認(rèn),事物要一件件識(shí)別,探究復(fù)雜的事物,都是分層拆解的思路。具體到前端開發(fā),客戶需求高頻變化,在并不純粹的瀏覽器方框之中,過(guò)分強(qiáng)調(diào)純粹的函數(shù)式編程肯定要誤人子弟。

見過(guò) React 家族的太多開發(fā)者,太多工具陷在追求 "純正" 的泥淖里,無(wú)法自拔,阿彌陀佛!但愿我的觀點(diǎn)是正確的。

?

本文參考資料:

阮一峰:MVC,MVP 和 MVVM 的圖示

facebook/flux:Flux Concepts

fluxxor.com:What is Flux?

Andrew Ray:The ReactJS Controller View Pattern

本專欄歷史文章:

介紹一項(xiàng)讓 React 可以與 Vue 抗衡的技術(shù)

React 可視化開發(fā)工具 Shadow Widget 非正經(jīng)入門(之一:React 三宗罪)

React 可視化開發(fā)工具 Shadow Widget 非正經(jīng)入門(之二:分離界面設(shè)計(jì))

React 可視化開發(fā)工具 Shadow Widget 非正經(jīng)入門(之三:雙源屬性與數(shù)據(jù)驅(qū)動(dòng))

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

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

相關(guān)文章

  • React 可視開發(fā)工具 Shadow Widget 正經(jīng)入門(之五:指令式界面設(shè)計(jì))

    摘要:本篇解釋中類的控制指令,與指令式界面設(shè)計(jì)相關(guān)。本專欄歷史文章介紹一項(xiàng)讓可以與抗衡的技術(shù)可視化開發(fā)工具非正經(jīng)入門之一三宗罪可視化開發(fā)工具非正經(jīng)入門之二分離界面設(shè)計(jì)可視化開發(fā)工具非正經(jīng)入門之三雙源屬性與數(shù)據(jù)驅(qū)動(dòng)可視化開發(fā)工具非正經(jīng)入門之四 本系列博文從 Shadow Widget 作者的視角,解釋該框架的設(shè)計(jì)要點(diǎn)。本篇解釋 Shadow Widget 中類 Vue 的控制指令,與指令式界面...

    pinecone 評(píng)論0 收藏0
  • React 可視開發(fā)工具 Shadow Widget 正經(jīng)入門(之一:React 三宗罪)

    摘要:前言非正經(jīng)入門是相對(duì)正經(jīng)入門而言的。不過(guò)不要緊,正式學(xué)習(xí)仍需回到正經(jīng)入門的方式??焖偃腴T建議先學(xué)會(huì)用拼文寫文檔注冊(cè)一個(gè)賬號(hào),把庫(kù)到自己名下,然后用這個(gè)庫(kù)寫自己的博客,參見這份介紹。會(huì)用拼文寫文章,相當(dāng)于開發(fā)已入門三分之一了。 本系列博文從 Shadow Widget 作者的視角,解釋該框架的設(shè)計(jì)要點(diǎn),既作為用戶手冊(cè)的補(bǔ)充,也從更本質(zhì)角度幫助大家理解 Shadow Widget 為什么這...

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

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

0條評(píng)論

閱讀需要支付1元查看
<