基于MVC理解React+Redux

我認(rèn)為MVC模式雖然已經(jīng)誕生了許多年,也有無數(shù)前端框架遵循了MVC模式,但我們?cè)谇岸碎_發(fā)時(shí),很多時(shí)候還是忽略了這個(gè)模式蘊(yùn)含的思想。該思想的核心就是職責(zé)分離,這種分離又隱含了“信息專家模式”的意義,直白地說,就是“專業(yè)的事情應(yīng)該交給專業(yè)的人去做”。

MVC(Model-View-Controller)的三個(gè)角色其實(shí)是各司其職:

  • model持有UI要展現(xiàn)的數(shù)據(jù)
  • View即UI的展現(xiàn)
  • Controller用于控制

以React來說,它就應(yīng)該只專注于View的呈現(xiàn),并將這些展現(xiàn)元素封裝為Component。這些Component要展現(xiàn)的props可以視為Model所持有的數(shù)據(jù)。

那么,什么情況下會(huì)導(dǎo)致View產(chǎn)生變化呢?從表象上看,似乎引起變化的原因是由于客戶端的某種請(qǐng)求或交互操作產(chǎn)生的事件。實(shí)則從業(yè)務(wù)上說,其實(shí)就是要改變Model的值,而UI的交互操作不過是對(duì)這種變化的界面展現(xiàn)罷了。換言之,View的變化其實(shí)應(yīng)該通過Model的變化來傳遞。

當(dāng)我們需要改變View時(shí),一種做法是直接在View上做文章,通過編寫針對(duì)UI元素的控制邏輯去改變View。另一種做法就是遵循MVC模式,應(yīng)該通過Controller去改變Model的結(jié)構(gòu),然后通知View去改變自己(或者理解為View偵聽到Model的變化,從而改變自己)。

React結(jié)合Redux框架做的正是這樣的事情。在設(shè)計(jì)React Component時(shí),我們需要通過UI的Layout來規(guī)劃我們的Component,包括Component的分解與組合。呈現(xiàn)Component的過程就可以抽象為一個(gè)函數(shù),這個(gè)函數(shù)接收一個(gè)輸入對(duì)象model,返回一個(gè)包裹了HTML元素與Model的DOM`結(jié)構(gòu)。如以下偽代碼:

const render = (model) => DOM

如果業(yè)務(wù)邏輯要求操作View的DOM,其實(shí)就是對(duì)DOM包裹的Model進(jìn)行操作,例如添加或修改某個(gè)<li>,其本質(zhì)是要添加或修改<li>元素中的值,這個(gè)值來自于Model。在Redux中,其實(shí)就是發(fā)起一個(gè)action。

執(zhí)行action的目的雖然是修改Model,不過在Redux中,我們盡量希望遵循FP的思想設(shè)計(jì)出所謂的“純函數(shù)”,于是Redux就引入了reducer函數(shù),這個(gè)函數(shù)要做的事情其實(shí)就是對(duì)Model進(jìn)行transform(可以考慮引入immutable.js來存儲(chǔ)和操作Modle)。一旦Model對(duì)象發(fā)生了變化(并不是真正發(fā)生了變化,而是產(chǎn)生了一個(gè)新的Model),Redux就會(huì)通知React Component根據(jù)新獲得的Model去重新Render。

顯然,React扮演的是View的角色,Redux則是Controller,至于Model就是Redux Store中存儲(chǔ)的State。我們要從MVC模式的角度去思考React+Redux開發(fā),把代碼需要做的每件事情想清楚,明確是誰的職責(zé),如此才不至于在實(shí)現(xiàn)時(shí)走歪路,不討好地去編寫大量View的控制邏輯,尤其是那些牽涉到parent-child組件的遞歸關(guān)系時(shí),可能會(huì)讓前端代碼燉成一鍋粥。

舉個(gè)實(shí)例。

我們要在前端編寫一個(gè)過濾器,UI展現(xiàn)與控制邏輯類似Logiform,如下圖所示:

Logiform的過濾器

這個(gè)過濾器可以理解為以Condition為根的一個(gè)遞歸嵌套樹形結(jié)構(gòu),枝為Group,而葉為Expression。Group還可以嵌套Group或者Expression??梢蕴砑?、刪除GroupExpression,也可以調(diào)整它們?cè)跇渲兴幍奈恢谩?/p>

針對(duì)這樣的需求,如果我們企圖在React Component中直接去操控和管理這些邏輯,就需要考慮Component的父子關(guān)系,還需要考慮添加或刪除Dom節(jié)點(diǎn)對(duì)整棵樹的影響。

如果我們站在前述MVC模式的角度來考慮過濾器樹的呈現(xiàn)與界面控制,其實(shí)不過就是針對(duì)Condition對(duì)象模型的操作罷了。這個(gè)時(shí)候,我們可以不用去操心DOM節(jié)點(diǎn)之間的關(guān)系,而是直接用React Component去render模型對(duì)象。對(duì)象的粗略結(jié)構(gòu)如下所示:

{ 
  "id": 1, 
  "operator": "and", 
  "conditions": [
    {
      "id": 2,
      "type": "expression",
      "operator": "=",
      "fieldId": "11000",
      "value": 3
    },
    {
      "id": 3,
      "type": "group",
      "operator": "or",
      "conditions": [
        {
          "id": 4,
          "type": "expression",
          "operator": "<=",
          "fieldId": "11001",
          "value": 20
        }
    ]
  }]
}

由于render是一種只讀的操作,要在React Component中去render這樣的結(jié)構(gòu)是非常容易的。如上,當(dāng)我們要?jiǎng)h除id為2的Expression時(shí),其實(shí)就是去編寫一個(gè)reducer,將其轉(zhuǎn)換為如下的對(duì)象:

{ 
  "id": 1, 
  "operator": "and", 
  "conditions": [
    {
      "id": 3,
      "type": "group",
      "operator": "or",
      "conditions": [
        {
          "id": 4,
          "type": "expression",
          "operator": "<=",
          "fieldId": "11001",
          "value": 20
        }
    ]
  }]
}

render對(duì)UI的呈現(xiàn)與控制邏輯完全相同,并不需要再去控制復(fù)雜的DOM。

概況下來,React+Redux的主體流程為:

  • 通過action獲得model,并將其作為state存儲(chǔ)到Store中;
  • 傳遞給React Component,按照某種設(shè)計(jì)呈現(xiàn)model數(shù)據(jù);
  • 調(diào)用action發(fā)起update請(qǐng)求,從而調(diào)用reducer生成新的state存儲(chǔ)到Store中;
  • redux通知React Component重新Render。

這是MVC三種角色各司其職相互協(xié)作的結(jié)果。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • React+Redux 這種開發(fā)模式在公司跌跌撞撞的使用已經(jīng)有五個(gè)月了。對(duì)這種開發(fā)模式進(jìn)行一個(gè)MVC的總結(jié)算也是跟...
    FanChengSheng閱讀 6,562評(píng)論 1 13
  • 原教程內(nèi)容詳見精益 React 學(xué)習(xí)指南,這只是我在學(xué)習(xí)過程中的一些閱讀筆記,個(gè)人覺得該教程講解深入淺出,比目前大...
    leonaxiong閱讀 2,954評(píng)論 1 18
  • React+Redux非常精煉,良好運(yùn)用將發(fā)揮出極強(qiáng)勁的生產(chǎn)力。但最大的挑戰(zhàn)來自于函數(shù)式編程(FP)范式。在工程化...
    小馬哥歸來閱讀 154,693評(píng)論 21 166
  • 做React需要會(huì)什么? react的功能其實(shí)很單一,主要負(fù)責(zé)渲染的功能,現(xiàn)有的框架,比如angular是一個(gè)大而...
    蒼都閱讀 14,967評(píng)論 1 139
  • 今天看吳軍老師的文章,成功并不難,在于少犯錯(cuò)誤。對(duì)我啟發(fā)很大。 在賭博的過程中,其實(shí)也就是你贏我一次,我贏你一次的...
    linhuizhang閱讀 570評(píng)論 0 1

友情鏈接更多精彩內(nèi)容