超详细解释 react,flux,redux 的概念与关系

🏷️ 365bet足球游戏 📅 2025-07-24 10:31:51 👤 admin 👀 8585 ⭐ 926
超详细解释 react,flux,redux 的概念与关系

生手碰到这个问题,也许会这样做:

当用户点击按钮的时候,先改变菜单名的色值,再改变按钮的背景图(由向下箭头,改成向上箭头),最后改变下拉列表的显示状态,有必要的话,还需要做个列表下拉的动画。当用户再次点击按钮的时候,把所有操作倒着来一遍,恢复菜单收起的状态,ok?

然而,对于好逸恶劳的前端老司机们来说,一般会这样做:对整个菜单的容器定义两个className,比如一个是"menu-close",一个是“menu-open”。在menu-close的状态下,菜单名的色值为黑色,按钮背景图为向下箭头,下拉列表是隐藏状态;在menu-open的状态下,菜单名的色值为白色,按钮背景图是向上箭头,下拉列表是显示状态;需要的话,再用css3 transition给下拉列表加个动画过渡效果。当用户点击按钮的时候,只需要改变整个菜单容器的className即可。所有的交互效果都用css“平铺”的方式声明出来,这样做不仅节省了多个手工步骤,而且更改整个容器的className是个单点操作,因此也方便维护和修改。这也是bootstrap框架里惯用的一招,非常好使。

通过这个例子,我们看到“改变state,让view自动更新”的开发思想在纯粹的前端领域也由来已久。它可以让开发者思维更加清晰,代码更好维护,幸福指数飙升!

然而用css className来实现state功能,其应用范围是非常有限的。原因很简单,css只能改变DOM元素的样式,却不能改变网页中DOM tree本身的结构(例如,例子1中todoList的增删操作就涉及li元素的append或者remove),更没有办法直接和具体的业务数据相关联。于是,knockoutjs、angularjs等前端框架纷纷登场,这些框架可以系统地实现view 和 state(一般在这些框架里称为ViewModel)的相互绑定,从而使代码更有秩序,帮前端开发省去不少麻烦。即便这些框架约定很多,有些束手束脚的感觉,但如果没有另一件大杀器重出江湖,程序猿们也可以将就过了,奈何既生瑜,何生亮。。这是后话。

(三)重剑无锋

好,抛开knockout、angular这些框架,现在如果让我们自己设计一套根据states(包括后台业务数据和前端临时数据,例如表单input值、某个面板的显隐状态等等)自动更新页面的机制,我们该怎么办呢?

对于每一种特定场景,我们也许有很多种代码方式来根据state自动更新页面的某个局部view。但是,如果页面交互足够复杂,以至于我们需要在页面的很多地方不断修修补补,并且这些“补丁”对应的state可能还彼此重叠,或者我们希望能一劳永逸地解决所有view自动更新的问题,并且还不引入更多繁琐的约定,似乎除了刷新整个页面没有更好的办法(这有点像逐帧动画的原理,我们一般不会真的根据物体运动轨迹一点一点修改画面,形成运动效果,而是直接一帧一帧*重绘整个画布,形成动画效果!)

但前面我们说过,像web1.0的做法一样,重绘整个页面对浏览器的性能损耗是很严重的,用户体验也很糟糕。。怎么办?怎么办?!我脑补着facebook的某个程序员在一个月黑风高的晚上坐在公司电脑前,抿了一口浓浓的咖啡,突然灵光一现,伴着屏幕上忽明忽暗的幽幽蓝光,在文本编辑器里写下这么一行文字:可不可以把浏览器里的DOM tree克隆一份完整的镜像到内存,也就是所谓的“virtual DOM”,当页面的state发生变化以后,根据最新的state重新生成一份virtual DOM(相当于在内存里“刷新”整个页面),将它和之前的virtual DOM做比对(diff),然后在浏览器里只渲染被改变的那部分内容,这样浏览器的性能损耗和用户体验不就都不成问题了吗?而我们知道在绝大部分网页应用中js引擎的性能和内存完全没有被充分利用,我们正好可以火力全开,利用js的这部分性能红利,实现内存中virtual DOM的diff工作,完美!

于是React横空出世。

话虽简单,不过单单是在内存中模拟整个DOM tree,这个工作想想就觉得头大,所以不得不佩服facebook的那些前端大神们!表面上react花了很大气力却只做了view层跟virtual DOM相关的工作,但所谓“大巧不工、重剑无锋”,实际上facebook祭出的这件大杀器让“改变state,view自动更新”这种直观朴素的想法有了坚实的基础,“state-view”的开发模式从此一马平川!正因为如此,伴随着react的崛起,类似于redux这些专注于管理state的轻量级框架也变得炙手可热起来。

有了React这把重剑,前端开发们第一次感觉到似乎又回到了web1.0美好的田园时代!而react非常具有表达力的jsx语法和完善的模块化结构,又让我们觉得像生活在酷炫的未来时代!这是我们的下一话题。( 此处应有《Back to The Future》的电影配乐)

(四)庖丁解牛(view的模块化)

view的组件化和模块化非常有利于分工协作、代码的积累复用以及单元测试。这对于提高团队开发的效率无疑具有非常重要的意义,这也是react广受青睐的重要原因之一,这一点就不再赘述。这里想换个角度,聊一下react的模块化机制,对于开发者个体来说有什么好处?

前面我们提到,由于React的“state-view”模式可以让开发者的大脑得到一种“单向流”的舒适体验。那为什么单向流的思维状态更加舒适呢?

这是因为在**单向流**状态下,要解决的问题如同一个函数映射,已知什么(比如state)是固定不变的,要得到什么(比如view)是定义明确,而人的思维非常习惯于这种定义明确的、没有“分叉”和“环路”的函数式问题。

也就是说,让人抓狂崩溃的往往是那些包含“分叉”或“环路”的非函数式问题,这个时候大脑不得不思前想后,谋划全局,进入一种“多线程”工作状态,而“单线程”作业对于大脑来说一般才是更加轻松高效。所谓“单线程”,就是每时每刻只专注于一个问题 —— one at a time! React的"state-view"模式帮助我们在开发view的时候,只需要专注于view(即关注页面布局样式。view上的交互行为怎样对state产生反馈作用,我们稍后再来讨论),而React简便的“模块化”机制(即只需要写很少量的boilerplate代码,就可以定义或引用一个新模块),让我们可以根据需要,将整个页面的布局样式工作进一步拆分成各个小模块(view component),或者将各个小模块组装成大模块,从而进一步深入贯彻“one at a time”的原则,给大脑减负,因此这时程序猿很容易进入一种舒适高效的状态(心理学中甚至有个“心流”的概念用来描述这种状态)。决定页面呈现的state可以通过模块属性(props)从父模块传递到子模块。这种"树状"分流机制,有点像植物将养分(state)从根部不断运输到细枝末叶的过程,如图所示:

相关推荐 ✨