成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

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

msup / 1666人閱讀

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

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

1. React Flux 框架

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

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

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

  Action -> Dispatcher -> Store -> View

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

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

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

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

2. React 中的 MVC

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

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

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

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

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

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

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

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

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

4. Shadow Widget 與 Redux 走在兩個方向上

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

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

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

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

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

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

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

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

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

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

6. 向 MVVM 演化

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

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

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

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

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

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

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

節(jié)點,完全勝任用來構(gòu)造 Store 節(jié)點。

其次,由前面總結(jié)的 Flux 中 Store 該具備的 3 項特性,與 MVVM 的雙向數(shù)據(jù)綁定需求高度重合,以 Shadow Widget 已實現(xiàn)的功能舉例:

雙源屬性具有事件通知功能,它可以被偵聽,修改雙源屬性的值可以觸發(fā)事件,刷新 trigger 表達式也能觸發(fā)事件。

將 Controller View 與 Store 合二為一,state 數(shù)據(jù)也合二為一,省去了兩者之間同步。

Shadow Widget 的可計算性屬性支持 any, all ,strict 三種條件同步機制,與 reflux 提供的條件組合等效。比如要求 Action AAction B 都發(fā)生后,才觸發(fā)事件,腳本表達式用 "all:" 前綴指示即可。

當然,這些 Flux 中 Store 的需求是附加在 React Component 之上的,如果 Component 想顯示界面(而不是用作純 Store,把界面隱藏起來),盡管顯示好了,無非這樣的節(jié)點還同時具備 Store 的功能。

改造后 Shadow Widget 的 MVVM 如下圖:

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

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

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

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

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

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

7. 對照 Vue 的 MVVM 舉個例子

一個 Vue 的 MVVM 例子如下。

對應于 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è)計,更傾向于函數(shù)式編程風格。比如:

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

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

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

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

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

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

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

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

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

引用它。

9. 總結(jié)

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

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

?

本文參考資料:

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

facebook/flux:Flux Concepts

fluxxor.com:What is Flux?

Andrew Ray:The ReactJS Controller View Pattern

本專欄歷史文章:

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

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

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

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

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

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/83453.html

相關(guān)文章

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

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

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

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

    dongxiawu 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<