摘要:在一些業(yè)務(wù)場(chǎng)景,我們期望父組件對(duì)于子組件的狀態(tài),擁有絕對(duì)的控制權(quán)。而對(duì)于前者則相反,由于組件內(nèi)部會(huì)有自己的狀態(tài),它內(nèi)部的渲染邏輯由父組件所傳與其內(nèi)部狀態(tài)共同決定。當(dāng)組件受控時(shí),其開關(guān)狀態(tài)應(yīng)該與屬性保持一致,反之,則和原來一樣。
08 使用 Control Props 目標(biāo)
在第七篇文章中,我們對(duì) toggle 組件進(jìn)行了重構(gòu),使父組件能夠傳入開關(guān)狀態(tài)的初始值,同時(shí)還可以傳入自定義的狀態(tài)重置邏輯。雖然父組件擁有了改變 toggle 組件內(nèi)部狀態(tài)的途徑,但是如果進(jìn)一步思考的話,父組件并沒有絕對(duì)的控制權(quán)。在一些業(yè)務(wù)場(chǎng)景,我們期望父組件對(duì)于子組件的狀態(tài),擁有絕對(duì)的控制權(quán)。
熟悉 React 的讀者一定不會(huì)對(duì)智能組件(Smart Component)和木偶組件(Dump Component)感到陌生。對(duì)于后者,其父組件一定對(duì)其擁有絕對(duì)控制權(quán),因?yàn)樗鼉?nèi)部沒有狀態(tài),渲染邏輯完全取決于父組件所傳 props 的值。而對(duì)于前者則相反,由于組件內(nèi)部會(huì)有自己的狀態(tài),它內(nèi)部的渲染邏輯由父組件所傳 props 與其內(nèi)部狀態(tài)共同決定。
這篇文章將著重解決這個(gè)問題,如果能夠使一個(gè)智能組件的狀態(tài)變得可控,即:
toggle 組件的開關(guān)狀態(tài)應(yīng)該完全由 prop 屬性 on 的值決定
當(dāng)沒有 on 屬性時(shí),toggle 組件的開關(guān)狀態(tài)降級(jí)為內(nèi)部管理
額外地,我們還將實(shí)現(xiàn)一個(gè)小需求,toggle 組件的開關(guān)狀態(tài)至多切換四次,如果超過四次,則需點(diǎn)擊重置后,才能夠重新對(duì)開關(guān)切換狀態(tài)進(jìn)行切換。
實(shí)現(xiàn) 判定組件是否受控由于 toggle 組件為一個(gè)智能組件,我們需要提供一個(gè)判定它是否受控的方式。很簡(jiǎn)單,由目標(biāo)中的第一點(diǎn)可知,當(dāng)父組件傳入了 on 屬性后,toggle 處于被控制的狀態(tài),否則則沒有,于是可以利用 Vue 組件的 computed 特性,聲明一個(gè) isOnControlled 計(jì)算屬性,如下:
computed: { isOnControlled() { return this.on !== undefined; } }
其內(nèi)部邏輯很簡(jiǎn)單,就是判定 prop 屬性 on 的值是否為 undefined,如果是,則未被父組件控制,反之,則被父組件控制。
更改 on 的聲明方式由于要滿足目標(biāo)中提及的第二點(diǎn),關(guān)于 prop 屬性 on 的聲明,我們要做出一些調(diào)整,如下:
on: { type: Boolean, default: undefined },
就是簡(jiǎn)單地將默認(rèn)值,由 false 改為了 undefined,這么做的原因是因?yàn)?,按照之前的寫法,如?on 未由父組件傳入,則默認(rèn)值為 false,那么 toggle 組件會(huì)認(rèn)為父組件實(shí)際傳入了一個(gè)值為 false 的 on 屬性,因此會(huì)將其內(nèi)部的開關(guān)狀態(tài)控制為關(guān),而非降級(jí)為內(nèi)部管理開關(guān)狀態(tài)。
實(shí)現(xiàn)狀態(tài)解析邏輯之前的實(shí)現(xiàn)中,通過 scope-slot 注入插槽的狀態(tài)完全取決于組件內(nèi)部 status 的值,我們需要改變狀態(tài)的注入邏輯。當(dāng)組件受控時(shí),其開關(guān)狀態(tài)應(yīng)該與 prop 屬性保持一致,反之,則和原來一樣。因此編寫一個(gè)叫做 controlledStatus 的計(jì)算屬性:
controlledStatus() { return this.isOnControlled ? { on: this.on } : this.status; }
這里利用了之前聲明的 isOnControlled 屬性來判斷當(dāng)前組件是否處于受控狀態(tài)。之后相應(yīng)地把模板中開關(guān)狀態(tài)的注入邏輯也進(jìn)行更改:
相應(yīng)地,除了開關(guān)狀態(tài)的注入邏輯,toggle 方法和 reset 方法的注入邏輯也需要更改,至于為什么,就交由讀者自行思考得出答案吧,這里簡(jiǎn)單羅列實(shí)現(xiàn)代碼,以供參考:
// toggle 方法 toggle() { if (this.isOnControlled) { this.$emit("toggle", !this.on); } else { this.status.on = !this.status.on; this.$emit("toggle", this.status.on); } } // reset 方法 reset() { if (this.isOnControlled) { Promise.resolve(this.onReset(!this.on)).then(on => { this.$emit("reset", on); }); } else { Promise.resolve(this.onReset(this.status.on)).then(on => { this.status.on = on || false; this.$emit("reset", this.status.on); }); } }
總體上的思路是,如果組件受控,則傳入回調(diào)方法中的開關(guān)狀態(tài)參數(shù),是在觸發(fā)相應(yīng)事件后,由 prop 屬性 on 得出的組件在下一時(shí)刻,應(yīng)當(dāng)處于的狀態(tài)。
這么說可能有點(diǎn)繞,換句話說就是,當(dāng)組件狀態(tài)發(fā)生更改時(shí),如果當(dāng)前的 on 屬性為 true(開關(guān)狀態(tài)為開),則組件本該處于關(guān)的狀態(tài),但由于組件受控,則它內(nèi)部不能直接將開關(guān)狀態(tài)更改為關(guān),而是依舊保持為開,但是它會(huì)將 false(開關(guān)狀態(tài)為關(guān))作為參數(shù)傳入觸發(fā)事件,這將告知父組件,當(dāng)前組件的下一個(gè)狀態(tài)為關(guān),至于父組件是否同意將其狀態(tài)更改為關(guān)則有父組件決定。
如果組件不受控,開關(guān)狀態(tài)由組件內(nèi)部自行管理,那和之前的實(shí)現(xiàn)邏輯是一模一樣的,保留之前的代碼即可。
成果當(dāng) toggle 組件被改造后,實(shí)現(xiàn)這個(gè)需求就很容易了。關(guān)于實(shí)現(xiàn)的代碼,這里就不進(jìn)行羅列了,有興趣可以通過在線代碼鏈接進(jìn)行查看,十分簡(jiǎn)單,這里僅簡(jiǎn)單附上一個(gè)最終的動(dòng)態(tài)效果圖:
你可以通過下面的鏈接來看看這個(gè)組件的實(shí)現(xiàn)代碼以及演示:
sandbox: 在線演示
github: part-8
總結(jié)關(guān)于 Controlled Component 和 Uncontrolled Component 的概念,我第一次是在 React 中關(guān)于表單的介紹中接觸到的。實(shí)際工作中,大部分對(duì)于狀態(tài)可控的需求也都存在于表單組件中,之所以存在這樣的需求,是因?yàn)楸韱蜗到y(tǒng)往往是復(fù)雜的,將其實(shí)現(xiàn)為智能組件,往往內(nèi)部狀態(tài)過于復(fù)雜,而如果實(shí)現(xiàn)為木偶組件,代碼結(jié)構(gòu)或者實(shí)現(xiàn)邏輯又過于繁瑣,這時(shí)如果可以借鑒這種模式的話,往往可以達(dá)到事半功倍的效果。
目錄github gist
關(guān)注公眾號(hào) 全棧101,只談技術(shù),不談人生
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/98766.html
摘要:寫在前頭去年,曾經(jīng)閱讀過一系列關(guān)于高級(jí)組件模式的文章,今年上半年,又抽空陸陸續(xù)續(xù)地翻譯了一系列關(guān)于高級(jí)組件模式的文章,碰巧最近接手了一個(gè)公司項(xiàng)目,前端這塊的技術(shù)棧是。同時(shí)這個(gè)組件還擁有一個(gè)屬性,用來初始化的狀態(tài)值。 寫在前頭 去年,曾經(jīng)閱讀過一系列關(guān)于高級(jí) react 組件模式的文章,今年上半年,又抽空陸陸續(xù)續(xù)地翻譯了一系列關(guān)于高級(jí) angular 組件模式的文章,碰巧最近接手了一個(gè)公...
摘要:并總結(jié)經(jīng)典面試題集各種算法和插件前端視頻源碼資源于一身的文檔,優(yōu)化項(xiàng)目,在瀏覽器端的層面上提升速度,幫助初中級(jí)前端工程師快速搭建項(xiàng)目。 本文是關(guān)注微信小程序的開發(fā)和面試問題,由基礎(chǔ)到困難循序漸進(jìn),適合面試和開發(fā)小程序。并總結(jié)vue React html css js 經(jīng)典面試題 集各種算法和插件、前端視頻源碼資源于一身的文檔,優(yōu)化項(xiàng)目,在瀏覽器端的層面上提升速度,幫助初中級(jí)前端工程師快...
摘要:并總結(jié)經(jīng)典面試題集各種算法和插件前端視頻源碼資源于一身的文檔,優(yōu)化項(xiàng)目,在瀏覽器端的層面上提升速度,幫助初中級(jí)前端工程師快速搭建項(xiàng)目。 本文是關(guān)注微信小程序的開發(fā)和面試問題,由基礎(chǔ)到困難循序漸進(jìn),適合面試和開發(fā)小程序。并總結(jié)vue React html css js 經(jīng)典面試題 集各種算法和插件、前端視頻源碼資源于一身的文檔,優(yōu)化項(xiàng)目,在瀏覽器端的層面上提升速度,幫助初中級(jí)前端工程師快...
摘要:并總結(jié)經(jīng)典面試題集各種算法和插件前端視頻源碼資源于一身的文檔,優(yōu)化項(xiàng)目,在瀏覽器端的層面上提升速度,幫助初中級(jí)前端工程師快速搭建項(xiàng)目。 本文是關(guān)注微信小程序的開發(fā)和面試問題,由基礎(chǔ)到困難循序漸進(jìn),適合面試和開發(fā)小程序。并總結(jié)vue React html css js 經(jīng)典面試題 集各種算法和插件、前端視頻源碼資源于一身的文檔,優(yōu)化項(xiàng)目,在瀏覽器端的層面上提升速度,幫助初中級(jí)前端工程師快...
閱讀 1834·2021-11-24 09:39
閱讀 2302·2021-09-30 09:47
閱讀 4169·2021-09-22 15:57
閱讀 1888·2019-08-29 18:36
閱讀 3589·2019-08-29 12:21
閱讀 599·2019-08-29 12:17
閱讀 1276·2019-08-29 11:25
閱讀 734·2019-08-28 18:26