摘要:同理,你只要知道改变状态能够实现要的功能,大体上的原理就是状态机就可以了。总结,本文重点状态机模式的使用场景,复杂多状态的管理,这里注意你没必要写个选项卡之类的用状态机,那反而是给自己找麻烦。
大家在写App和一些单页面程序的时候,经常会遇到这样的情况:
当点击左边的箭头的时候,会出现灰黑色的抽屉效果,再点击一下向左的箭头,就会收起来,当然向右滑动和向左滑动也能实现抽屉效果的开关。还有,当抽屉效果开着的时候,点击右侧区域也会自动收起抽屉。点击左侧抽屉里面的图标,那么也会发生抽屉效果的开关。
如果我们用原生js去手动控制抽屉的开关效果,随着逻辑的复杂,会存在两个严重的问题:
1.如果只是向左箭头点击一次开,再点击一次关成对儿出现还好,但是如果出现比如点击一下左侧按钮或者点击右侧内容区域关闭就容易出现点击关闭不掉或者不该关闭的情况下关闭了,抽屉状态的控制会随着业务逻辑的复杂度增加变得十分不可控。
2.如果要想增加一个逻辑控制抽屉开关,那么就得从一堆的if else 详细代码里,找到最后的else 部分增加else if,一来是修改起来非常困难,而来如果遇上条件组合判断和嵌套,对于开发者简直是一个噩梦,如果出现一个bug,你得把所有的逻辑捋顺一遍,这对于一个复杂的项目是非常耗时,几乎是不可能的。
由于app越来越复杂,视图随着数据和逻辑的手动更新状态变得越来越困难。在这种情况下,Angualr、React、Vue等框架应运而生。尤其是React,在状态管理无出其右。那么问题来了,为什么React就在状态管理方面游刃有余呢?
因为它使用了状态模式。这事儿其实非常的简单,我们看看怎么回事儿。
状态模式(状态机)
什么是状态模式或状态机?
一个对象在其内部状态改变时改变它的行为,这个对象看起来就像改变了它的类一样。
当大家看到定义的时候,是不是有一种单个字都认识合起来完全看不懂的感觉?这就好比直播吃翔四个字,单看这四个字感觉没啥,合起来就感觉怎么这么恶心。
不过没关系,我们来看看状态模式到底是个啥玩意。大家千万别听见设计模式和状态机之类的词语自己先蒙圈吓到了,我直接写一个状态机,你一看就明白。
大家家里都用过冰箱吧,点击电源按钮.如果是洗衣机是开着的on状态, 当你点击它会发出off的信号,如果你是off状态,则会发出on的信号.代码实现如下:
var switches = (function(){ var state = "off"; return function(){ if(state === "off"){ console.log("打开洗衣机"); state = "on"; }else if(state === "on"){ console.log("关闭洗衣机"); state = "off"; } } })(); //按下开关按钮 oBtn.onclick = function(){ switches(); };
上面的代码完全符合我们学过的js的东西,简单的一个匿名函数自执行,加一个变量,ok这就是一个状态机,是不是so easy。
但是作为一个有追求的洗衣机,得能够针对不同的洗衣机选择的不同的程序,没错洗衣机面板上也是程序这两个字,发明洗衣机的一定是程序员。
程序里面有很多的洗涤方式,比如智能、标准、快速、强力,轻柔等等。我们丰富一下我们的面板。
var switches = (function(){ var state = "智能"; return function(){ if(state === "智能"){ console.log("智能洗衣模式"); state = "标准"; }else if(state === "标准"){ console.log("标准洗衣模式"); state = "快速"; }else if(state === "快速"){ console.log("快速洗衣模式"); state = "强力"; }else if(state === "强力"){ console.log("强力洗衣模式"); state = "轻柔"; }else if(state === "轻柔"){ console.log("轻柔洗衣模式"); state = "智能"; } } })(); //按下程序按钮 oBtn.onclick = function(){ switches(); };
看起来没问题,但是你懂的,首先写10中洗衣模式if写法会被写死,switch方式也很不好。
我有一个大胆的想法,能不能不用判断语句?大家看我这么思考能不能搞定这件事?
其实洗衣机面板其实就是一个状态对应一个行为,
一个对象在其内部状态改变时改变它的行为,这个对象看起来就像改变了它的类一样。
这句话就好理解了,大家想洗衣机如果本来是浸泡状态,但是我把它改成脱水状态,洗衣机从最开始的浸泡衣服变成甩干衣服,看起来就好像洗衣机从一个浸泡机器变成了甩干机器一样。
换成这种思路理解,我们就可以不用判断了,只要记住状态改变,行为改变就行了。我们试着实现一下洗衣模式。
Document
这样就拜托了if判断,我们想要什么模式,只需要通过改变对应的状态就好了。但是很多人会想说:
大量重复代码太难受了啊,针对这样的情况,es6中推出了状态机这个伪函数,能够帮助我们快速实现状态化。
也就是传说中的generator函数。 目前FF,edge,chrome 最新版本已经支持。
generator
我们用generator优化一下我们上面的代码:
Document
这里我解释下,Generator 函数是一个普通函数,但是有三个特征:
1.function关键字与函数名之间有一个星号;
2.函数体内部使用yield表达式,定义不同的内部状态
3.遍历器对象的next方法,使得指针移向下一个状态
简单的说generator就是让函数排队一个一个去执行了,很简单对不对。
上面我们说过react的状态管理无出其右,那我们看看它的状态管理跟我们写的有什么异同之处呢?
react的状态管理
我们平时开发组件时很多时候要切换组件的状态,每种状态有不同的处理方式,这个时候就可以使用状态模式进行开发。
用和上面一样的思路,我们来举一个React组件的小例子,比如一个Banner导航,最基本的两种状态,显示和隐藏,如下:
我们先把generator思路翻篇,我们回到状态模式,先看一段代码
const States = { "show": function () { console.log("banner展现状态,点击关闭"); this.setState({ currentState: "hide" }) }, "hide": function () { console.log("banner关闭状态,点击展现"); this.setState({ currentState: "show" }) } };
大家现在来看,这个不就是“react版本的洗衣机”嘛。只不过我们定义的是单个的状态变量,而这里通过一个对象States来定义banner的状态,这里有两种状态show和hide,分别拥有相应的处理方法,调用后再分别把当前banner改写为另外一种状态。
接下来来看导航类Banner,这里吧状态要给拿过来做对照了,这样看着醒目:
const States = { "show": function () { console.log("banner展现状态,点击关闭"); this.setState({ currentState: "hide" }) }, "hide": function () { console.log("banner关闭状态,点击展现"); this.setState({ currentState: "show" }) } }; //上面代码不该出现在这只是为了说明问题 class Banner extends Component { constructor(props) { super(props); this.state = { currentState: "hide" } this.toggle = this.toggle.bind(this); } toggle() { const s = this.state.currentState; States[s] && States[s].apply(this); } render() { const { currentState } = this.state; return (); } }; export default Banner;
通过导航组件大家这么想,其实react就是有很多种洗衣状态但是一定能数出来多少种洗衣模式的洗衣机,我们每一次的操作都是在按洗衣机的按钮。上面的代码只不过是再开关洗衣机而已。
你不用纠结为什么这么做就能够进行状态管理。
你用洗衣机强力模式的时候,你也没考虑过洗衣机桶和马达怎么运作的吧?你只要知道按下哪个按钮能洗干净衣服,大体上知道洗衣机里面是通过马达带动衣服和滚筒之间摩擦清除污渍就够了。
同理,你只要知道改变状态能够实现要的功能,大体上的原理就是状态机就可以了。
有了这个基础,如果想继续深入就可以去看react源码以及进行各种开发了。
总结,本文重点:
1.状态机模式的使用场景,复杂多状态的管理,这里注意你没必要写个选项卡之类的用状态机,那反而是给自己找麻烦。技术源于生活和解决问题,你洗一双袜子也不会扔洗衣机里面吧?
2.generaor的使用,这个大家要学会和灵活运用,我只是浅显的讲了基础的应用,这个对你的开发和代码简化会大有用途。
3.react的状态管理,大家要知道原理,重在应用,等用多了你再去看源码,就能够更加深刻的体会作者为什么那么写,原理和熟练应用一个都不能少,但是要注意先后顺序和特定学习阶段该了解到的程度。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/109591.html
摘要:根据百度百科的说法迭代器模式,又叫做游标模式。给出的定义为提供一种方法访问一个容器对象中各个元素,而又不需暴露该对象的内部细节。从定义可见,迭代器模式是为容器而生。很明显,对容器对象的访问必然涉及到遍历算法。这两种情况好像都能够解决问题。 Iterator根据百度百科的说法: 迭代器(Iterator)模式,又叫做游标(Cursor)模式。GOF给出的定义为:提供一种方法访问一个容器(...
摘要:介一回聊状态模式,官方描述允许一个对象在其内部状态改变时改变它的行为。有限状态机有限状态机是一个非常有用的模型,可以模拟世界上大部分事物。这个是官方说法,简单说,她有三个特征,状态总数是有限的。,任一时刻,只处在一种状态之中。 本回内容介绍 上一回聊了聊组合模式(Composite),用组合模式模拟了个图片库,聊了递归。介一回聊状态模式(State),官方描述允许一个对象在其内部状态改...
摘要:组建属性初始化默认值类型在中将下面的代码替换成下面的代码最后一步将初始状态从构造函数中转变成属性初始化。在构造函数的后天添加正确的代码你需要把状态初始化代码从构造函数中删除。 这是React和ECMAScript6结合使用系列文章的第二篇。 下面是所有系列文章章节的链接: React 、 ES6 - 介绍(第一部分) React类、ES7属性初始化(第二部分) React类,方法绑定...
摘要:前端与状态现在的前端开发中,对于状态的管理是重中之重。有限状态机那么如何更好的管理前端软件的复杂度的状态机思想给出了自己的答案。有限状态机并不是一个复杂的概念简单说,它有三个特征状态总数是有限的。 前提 在现在的前端社区,关于MVVM、Model driven view 之类的概念,已经算是非常普及了。React/Vue 这类框架可以算是代表。而自己虽然有 React/Vue 的使用经...
摘要:集成到去使用如果想在中使用,想到比较方便的使用形式是高阶组件,需要用到有限状态机的组件传进高阶组件,就立马拥有了使用有限状态机的能力。 背景 近年来由于一些前端框架的兴起而后逐渐成熟,组件化的概念已经深入人心,为了管理好大型应用中错综复杂的组件,又有了单向数据流的思想指引着我们,Vuex、Redux、MobX等状态管理工具也许大家都信手拈来。我们手握着这些工具,不断思考着哪些数据应该放...
阅读 3100·2021-09-09 11:39
阅读 1211·2021-09-09 09:33
阅读 1085·2019-08-30 15:43
阅读 518·2019-08-29 14:08
阅读 1715·2019-08-26 13:49
阅读 2358·2019-08-26 10:09
阅读 1528·2019-08-23 17:13
阅读 2267·2019-08-23 12:57