我認爲MVC模式雖然已經誕生了許多年,也有無數前端框架遵循了MVC模式,但咱們在前端開發時,不少時候仍是忽略了這個模式蘊含的思想。該思想的核心就是職責分離,這種分離又隱含了「信息專家模式」的意義,直白地說,就是「專業的事情應該交給專業的人去作」。javascript
MVC(Model-View-Controller)的三個角色實際上是各司其職:前端
以React來講,它就應該只專一於View的呈現,並將這些展示元素封裝爲Component。這些Component要展示的props能夠視爲Model所持有的數據。java
那麼,什麼狀況下會致使View產生變化呢?從表象上看,彷佛引發變化的緣由是因爲客戶端的某種請求或交互操做產生的事件。實則從業務上說,其實就是要改變Model的值,而UI的交互操做不過是對這種變化的界面展示罷了。換言之,View的變化其實應該經過Model的變化來傳遞。express
當咱們須要改變View時,一種作法是直接在View上作文章,經過編寫針對UI元素的控制邏輯去改變View。另外一種作法就是遵循MVC模式,應該經過Controller去改變Model的結構,而後通知View去改變本身(或者理解爲View偵聽到Model的變化,從而改變本身)。json
React結合Redux框架作的正是這樣的事情。在設計React Component
時,咱們須要經過UI的Layout來規劃咱們的Component,包括Component的分解與組合。呈現Component的過程就能夠抽象爲一個函數,這個函數接收一個輸入對象model,返回一個包裹了HTML元素與Model的
DOM`結構。如如下僞代碼:redux
const render = (model) => DOM複製代碼
若是業務邏輯要求操做View的DOM,其實就是對DOM包裹的Model進行操做,例如添加或修改某個<li>
,其本質是要添加或修改<li>
元素中的值,這個值來自於Model。在Redux中,其實就是發起一個action
。前端框架
執行action
的目的雖然是修改Model
,不過在Redux中,咱們儘可能但願遵循FP的思想設計出所謂的「純函數」,因而Redux就引入了reducer
函數,這個函數要作的事情其實就是對Model
進行transform
(能夠考慮引入immutable.js來存儲和操做Modle)。一旦Model
對象發生了變化(並非真正發生了變化,而是產生了一個新的Model),Redux就會通知React Component根據新得到的Model
去從新Render。框架
顯然,React扮演的是View的角色,Redux則是Controller,至於Model就是Redux Store中存儲的State。咱們要從MVC模式的角度去思考React+Redux開發,把代碼須要作的每件事情想清楚,明確是誰的職責,如此纔不至於在實現時走歪路,不討好地去編寫大量View的控制邏輯,尤爲是那些牽涉到parent-child組件的遞歸關係時,可能會讓前端代碼燉成一鍋粥。函數
舉個實例。spa
咱們要在前端編寫一個過濾器,UI展示與控制邏輯相似Logiform,以下圖所示:
這個過濾器能夠理解爲以Condition
爲根的一個遞歸嵌套樹形結構,枝爲Group
,而葉爲Expression
。Group
還能夠嵌套Group
或者Expression
。能夠添加、刪除Group
或Expression
,也能夠調整它們在樹中所處的位置。
針對這樣的需求,若是咱們企圖在React Component中直接去操控和管理這些邏輯,就須要考慮Component的父子關係,還須要考慮添加或刪除Dom節點對整棵樹的影響。
若是咱們站在前述MVC模式的角度來考慮過濾器樹的呈現與界面控制,其實不過就是針對Condition
對象模型的操做罷了。這個時候,咱們能夠不用去操心DOM節點之間的關係,而是直接用React Component去render模型對象。對象的粗略結構以下所示:
{
"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這樣的結構是很是容易的。如上,當咱們要刪除id
爲2的Expression
時,其實就是去編寫一個reducer,將其轉換爲以下的對象:
{
"id": 1,
"operator": "and",
"conditions": [
{
"id": 3,
"type": "group",
"operator": "or",
"conditions": [
{
"id": 4,
"type": "expression",
"operator": "<=",
"fieldId": "11001",
"value": 20
}
]
}]
}複製代碼
render
對UI的呈現與控制邏輯徹底相同,並不須要再去控制複雜的DOM。
概況下來,React+Redux的主體流程爲:
這是MVC三種角色各司其職相互協做的結果。