我认为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三种角色各司其职相互协做的结果。