摘要:同理,你只要知道改變狀態(tài)能夠?qū)崿F(xiàn)要的功能,大體上的原理就是狀態(tài)機(jī)就可以了。總結(jié),本文重點(diǎn)狀態(tài)機(jī)模式的使用場(chǎng)景,復(fù)雜多狀態(tài)的管理,這里注意你沒(méi)必要寫(xiě)個(gè)選項(xiàng)卡之類的用狀態(tài)機(jī),那反而是給自己找麻煩。
大家在寫(xiě)App和一些單頁(yè)面程序的時(shí)候,經(jīng)常會(huì)遇到這樣的情況:
當(dāng)點(diǎn)擊左邊的箭頭的時(shí)候,會(huì)出現(xiàn)灰黑色的抽屜效果,再點(diǎn)擊一下向左的箭頭,就會(huì)收起來(lái),當(dāng)然向右滑動(dòng)和向左滑動(dòng)也能實(shí)現(xiàn)抽屜效果的開(kāi)關(guān)。還有,當(dāng)抽屜效果開(kāi)著的時(shí)候,點(diǎn)擊右側(cè)區(qū)域也會(huì)自動(dòng)收起抽屜。點(diǎn)擊左側(cè)抽屜里面的圖標(biāo),那么也會(huì)發(fā)生抽屜效果的開(kāi)關(guān)。
如果我們用原生js去手動(dòng)控制抽屜的開(kāi)關(guān)效果,隨著邏輯的復(fù)雜,會(huì)存在兩個(gè)嚴(yán)重的問(wèn)題:
1.如果只是向左箭頭點(diǎn)擊一次開(kāi),再點(diǎn)擊一次關(guān)成對(duì)兒出現(xiàn)還好,但是如果出現(xiàn)比如點(diǎn)擊一下左側(cè)按鈕或者點(diǎn)擊右側(cè)內(nèi)容區(qū)域關(guān)閉就容易出現(xiàn)點(diǎn)擊關(guān)閉不掉或者不該關(guān)閉的情況下關(guān)閉了,抽屜狀態(tài)的控制會(huì)隨著業(yè)務(wù)邏輯的復(fù)雜度增加變得十分不可控。
2.如果要想增加一個(gè)邏輯控制抽屜開(kāi)關(guān),那么就得從一堆的if else 詳細(xì)代碼里,找到最后的else 部分增加else if,一來(lái)是修改起來(lái)非常困難,而來(lái)如果遇上條件組合判斷和嵌套,對(duì)于開(kāi)發(fā)者簡(jiǎn)直是一個(gè)噩夢(mèng),如果出現(xiàn)一個(gè)bug,你得把所有的邏輯捋順一遍,這對(duì)于一個(gè)復(fù)雜的項(xiàng)目是非常耗時(shí),幾乎是不可能的。
由于app越來(lái)越復(fù)雜,視圖隨著數(shù)據(jù)和邏輯的手動(dòng)更新?tīng)顟B(tài)變得越來(lái)越困難。在這種情況下,Angualr、React、Vue等框架應(yīng)運(yùn)而生。尤其是React,在狀態(tài)管理無(wú)出其右。那么問(wèn)題來(lái)了,為什么React就在狀態(tài)管理方面游刃有余呢?
因?yàn)樗褂昧藸顟B(tài)模式。這事兒其實(shí)非常的簡(jiǎn)單,我們看看怎么回事兒。
狀態(tài)模式(狀態(tài)機(jī))
什么是狀態(tài)模式或狀態(tài)機(jī)?
一個(gè)對(duì)象在其內(nèi)部狀態(tài)改變時(shí)改變它的行為,這個(gè)對(duì)象看起來(lái)就像改變了它的類一樣。
當(dāng)大家看到定義的時(shí)候,是不是有一種單個(gè)字都認(rèn)識(shí)合起來(lái)完全看不懂的感覺(jué)?這就好比直播吃翔四個(gè)字,單看這四個(gè)字感覺(jué)沒(méi)啥,合起來(lái)就感覺(jué)怎么這么惡心。
不過(guò)沒(méi)關(guān)系,我們來(lái)看看狀態(tài)模式到底是個(gè)啥玩意。大家千萬(wàn)別聽(tīng)見(jiàn)設(shè)計(jì)模式和狀態(tài)機(jī)之類的詞語(yǔ)自己先蒙圈嚇到了,我直接寫(xiě)一個(gè)狀態(tài)機(jī),你一看就明白。
大家家里都用過(guò)冰箱吧,點(diǎn)擊電源按鈕.如果是洗衣機(jī)是開(kāi)著的on狀態(tài), 當(dāng)你點(diǎn)擊它會(huì)發(fā)出off的信號(hào),如果你是off狀態(tài),則會(huì)發(fā)出on的信號(hào).代碼實(shí)現(xiàn)如下:
var switches = (function(){ var state = "off"; return function(){ if(state === "off"){ console.log("打開(kāi)洗衣機(jī)"); state = "on"; }else if(state === "on"){ console.log("關(guān)閉洗衣機(jī)"); state = "off"; } } })(); //按下開(kāi)關(guān)按鈕 oBtn.onclick = function(){ switches(); };
上面的代碼完全符合我們學(xué)過(guò)的js的東西,簡(jiǎn)單的一個(gè)匿名函數(shù)自執(zhí)行,加一個(gè)變量,ok這就是一個(gè)狀態(tài)機(jī),是不是so easy。
但是作為一個(gè)有追求的洗衣機(jī),得能夠針對(duì)不同的洗衣機(jī)選擇的不同的程序,沒(méi)錯(cuò)洗衣機(jī)面板上也是程序這兩個(gè)字,發(fā)明洗衣機(jī)的一定是程序員。
程序里面有很多的洗滌方式,比如智能、標(biāo)準(zhǔn)、快速、強(qiáng)力,輕柔等等。我們豐富一下我們的面板。
var switches = (function(){ var state = "智能"; return function(){ if(state === "智能"){ console.log("智能洗衣模式"); state = "標(biāo)準(zhǔn)"; }else if(state === "標(biāo)準(zhǔn)"){ console.log("標(biāo)準(zhǔn)洗衣模式"); state = "快速"; }else if(state === "快速"){ console.log("快速洗衣模式"); state = "強(qiáng)力"; }else if(state === "強(qiáng)力"){ console.log("強(qiáng)力洗衣模式"); state = "輕柔"; }else if(state === "輕柔"){ console.log("輕柔洗衣模式"); state = "智能"; } } })(); //按下程序按鈕 oBtn.onclick = function(){ switches(); };
看起來(lái)沒(méi)問(wèn)題,但是你懂的,首先寫(xiě)10中洗衣模式if寫(xiě)法會(huì)被寫(xiě)死,switch方式也很不好。
我有一個(gè)大膽的想法,能不能不用判斷語(yǔ)句?大家看我這么思考能不能搞定這件事?
其實(shí)洗衣機(jī)面板其實(shí)就是一個(gè)狀態(tài)對(duì)應(yīng)一個(gè)行為,
一個(gè)對(duì)象在其內(nèi)部狀態(tài)改變時(shí)改變它的行為,這個(gè)對(duì)象看起來(lái)就像改變了它的類一樣。
這句話就好理解了,大家想洗衣機(jī)如果本來(lái)是浸泡狀態(tài),但是我把它改成脫水狀態(tài),洗衣機(jī)從最開(kāi)始的浸泡衣服變成甩干衣服,看起來(lái)就好像洗衣機(jī)從一個(gè)浸泡機(jī)器變成了甩干機(jī)器一樣。
換成這種思路理解,我們就可以不用判斷了,只要記住狀態(tài)改變,行為改變就行了。我們?cè)囍鴮?shí)現(xiàn)一下洗衣模式。
Document
這樣就拜托了if判斷,我們想要什么模式,只需要通過(guò)改變對(duì)應(yīng)的狀態(tài)就好了。但是很多人會(huì)想說(shuō):
大量重復(fù)代碼太難受了啊,針對(duì)這樣的情況,es6中推出了狀態(tài)機(jī)這個(gè)偽函數(shù),能夠幫助我們快速實(shí)現(xiàn)狀態(tài)化。
也就是傳說(shuō)中的generator函數(shù)。 目前FF,edge,chrome 最新版本已經(jīng)支持。
generator
我們用generator優(yōu)化一下我們上面的代碼:
Document
這里我解釋下,Generator 函數(shù)是一個(gè)普通函數(shù),但是有三個(gè)特征:
1.function關(guān)鍵字與函數(shù)名之間有一個(gè)星號(hào);
2.函數(shù)體內(nèi)部使用yield表達(dá)式,定義不同的內(nèi)部狀態(tài)
3.遍歷器對(duì)象的next方法,使得指針移向下一個(gè)狀態(tài)
簡(jiǎn)單的說(shuō)generator就是讓函數(shù)排隊(duì)一個(gè)一個(gè)去執(zhí)行了,很簡(jiǎn)單對(duì)不對(duì)。
上面我們說(shuō)過(guò)react的狀態(tài)管理無(wú)出其右,那我們看看它的狀態(tài)管理跟我們寫(xiě)的有什么異同之處呢?
react的狀態(tài)管理
我們平時(shí)開(kāi)發(fā)組件時(shí)很多時(shí)候要切換組件的狀態(tài),每種狀態(tài)有不同的處理方式,這個(gè)時(shí)候就可以使用狀態(tài)模式進(jìn)行開(kāi)發(fā)。
用和上面一樣的思路,我們來(lái)舉一個(gè)React組件的小例子,比如一個(gè)Banner導(dǎo)航,最基本的兩種狀態(tài),顯示和隱藏,如下:
我們先把generator思路翻篇,我們回到狀態(tài)模式,先看一段代碼
const States = { "show": function () { console.log("banner展現(xiàn)狀態(tài),點(diǎn)擊關(guān)閉"); this.setState({ currentState: "hide" }) }, "hide": function () { console.log("banner關(guān)閉狀態(tài),點(diǎn)擊展現(xiàn)"); this.setState({ currentState: "show" }) } };
大家現(xiàn)在來(lái)看,這個(gè)不就是“react版本的洗衣機(jī)”嘛。只不過(guò)我們定義的是單個(gè)的狀態(tài)變量,而這里通過(guò)一個(gè)對(duì)象States來(lái)定義banner的狀態(tài),這里有兩種狀態(tài)show和hide,分別擁有相應(yīng)的處理方法,調(diào)用后再分別把當(dāng)前banner改寫(xiě)為另外一種狀態(tài)。
接下來(lái)來(lái)看導(dǎo)航類Banner,這里吧狀態(tài)要給拿過(guò)來(lái)做對(duì)照了,這樣看著醒目:
const States = { "show": function () { console.log("banner展現(xiàn)狀態(tài),點(diǎn)擊關(guān)閉"); this.setState({ currentState: "hide" }) }, "hide": function () { console.log("banner關(guān)閉狀態(tài),點(diǎn)擊展現(xiàn)"); this.setState({ currentState: "show" }) } }; //上面代碼不該出現(xiàn)在這只是為了說(shuō)明問(wèn)題 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;
通過(guò)導(dǎo)航組件大家這么想,其實(shí)react就是有很多種洗衣?tīng)顟B(tài)但是一定能數(shù)出來(lái)多少種洗衣模式的洗衣機(jī),我們每一次的操作都是在按洗衣機(jī)的按鈕。上面的代碼只不過(guò)是再開(kāi)關(guān)洗衣機(jī)而已。
你不用糾結(jié)為什么這么做就能夠進(jìn)行狀態(tài)管理。
你用洗衣機(jī)強(qiáng)力模式的時(shí)候,你也沒(méi)考慮過(guò)洗衣機(jī)桶和馬達(dá)怎么運(yùn)作的吧?你只要知道按下哪個(gè)按鈕能洗干凈衣服,大體上知道洗衣機(jī)里面是通過(guò)馬達(dá)帶動(dòng)衣服和滾筒之間摩擦清除污漬就夠了。
同理,你只要知道改變狀態(tài)能夠?qū)崿F(xiàn)要的功能,大體上的原理就是狀態(tài)機(jī)就可以了。
有了這個(gè)基礎(chǔ),如果想繼續(xù)深入就可以去看react源碼以及進(jìn)行各種開(kāi)發(fā)了。
總結(jié),本文重點(diǎn):
1.狀態(tài)機(jī)模式的使用場(chǎng)景,復(fù)雜多狀態(tài)的管理,這里注意你沒(méi)必要寫(xiě)個(gè)選項(xiàng)卡之類的用狀態(tài)機(jī),那反而是給自己找麻煩。技術(shù)源于生活和解決問(wèn)題,你洗一雙襪子也不會(huì)扔洗衣機(jī)里面吧?
2.generaor的使用,這個(gè)大家要學(xué)會(huì)和靈活運(yùn)用,我只是淺顯的講了基礎(chǔ)的應(yīng)用,這個(gè)對(duì)你的開(kāi)發(fā)和代碼簡(jiǎn)化會(huì)大有用途。
3.react的狀態(tài)管理,大家要知道原理,重在應(yīng)用,等用多了你再去看源碼,就能夠更加深刻的體會(huì)作者為什么那么寫(xiě),原理和熟練應(yīng)用一個(gè)都不能少,但是要注意先后順序和特定學(xué)習(xí)階段該了解到的程度。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/109591.html
摘要:根據(jù)百度百科的說(shuō)法迭代器模式,又叫做游標(biāo)模式。給出的定義為提供一種方法訪問(wèn)一個(gè)容器對(duì)象中各個(gè)元素,而又不需暴露該對(duì)象的內(nèi)部細(xì)節(jié)。從定義可見(jiàn),迭代器模式是為容器而生。很明顯,對(duì)容器對(duì)象的訪問(wèn)必然涉及到遍歷算法。這兩種情況好像都能夠解決問(wèn)題。 Iterator根據(jù)百度百科的說(shuō)法: 迭代器(Iterator)模式,又叫做游標(biāo)(Cursor)模式。GOF給出的定義為:提供一種方法訪問(wèn)一個(gè)容器(...
摘要:介一回聊狀態(tài)模式,官方描述允許一個(gè)對(duì)象在其內(nèi)部狀態(tài)改變時(shí)改變它的行為。有限狀態(tài)機(jī)有限狀態(tài)機(jī)是一個(gè)非常有用的模型,可以模擬世界上大部分事物。這個(gè)是官方說(shuō)法,簡(jiǎn)單說(shuō),她有三個(gè)特征,狀態(tài)總數(shù)是有限的。,任一時(shí)刻,只處在一種狀態(tài)之中。 本回內(nèi)容介紹 上一回聊了聊組合模式(Composite),用組合模式模擬了個(gè)圖片庫(kù),聊了遞歸。介一回聊狀態(tài)模式(State),官方描述允許一個(gè)對(duì)象在其內(nèi)部狀態(tài)改...
摘要:組建屬性初始化默認(rèn)值類型在中將下面的代碼替換成下面的代碼最后一步將初始狀態(tài)從構(gòu)造函數(shù)中轉(zhuǎn)變成屬性初始化。在構(gòu)造函數(shù)的后天添加正確的代碼你需要把狀態(tài)初始化代碼從構(gòu)造函數(shù)中刪除。 這是React和ECMAScript6結(jié)合使用系列文章的第二篇。 下面是所有系列文章章節(jié)的鏈接: React 、 ES6 - 介紹(第一部分) React類、ES7屬性初始化(第二部分) React類,方法綁定...
摘要:前端與狀態(tài)現(xiàn)在的前端開(kāi)發(fā)中,對(duì)于狀態(tài)的管理是重中之重。有限狀態(tài)機(jī)那么如何更好的管理前端軟件的復(fù)雜度的狀態(tài)機(jī)思想給出了自己的答案。有限狀態(tài)機(jī)并不是一個(gè)復(fù)雜的概念簡(jiǎn)單說(shuō),它有三個(gè)特征狀態(tài)總數(shù)是有限的。 前提 在現(xiàn)在的前端社區(qū),關(guān)于MVVM、Model driven view 之類的概念,已經(jīng)算是非常普及了。React/Vue 這類框架可以算是代表。而自己雖然有 React/Vue 的使用經(jīng)...
摘要:集成到去使用如果想在中使用,想到比較方便的使用形式是高階組件,需要用到有限狀態(tài)機(jī)的組件傳進(jìn)高階組件,就立馬擁有了使用有限狀態(tài)機(jī)的能力。 背景 近年來(lái)由于一些前端框架的興起而后逐漸成熟,組件化的概念已經(jīng)深入人心,為了管理好大型應(yīng)用中錯(cuò)綜復(fù)雜的組件,又有了單向數(shù)據(jù)流的思想指引著我們,Vuex、Redux、MobX等狀態(tài)管理工具也許大家都信手拈來(lái)。我們手握著這些工具,不斷思考著哪些數(shù)據(jù)應(yīng)該放...
閱讀 3419·2021-09-09 11:39
閱讀 1260·2021-09-09 09:33
閱讀 1165·2019-08-30 15:43
閱讀 582·2019-08-29 14:08
閱讀 1759·2019-08-26 13:49
閱讀 2412·2019-08-26 10:09
閱讀 1576·2019-08-23 17:13
閱讀 2325·2019-08-23 12:57