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