這篇文章寫的較早,是剛接觸RN的時候進行的思考總結,是一個分析的過程,您還可以參考思想更成熟一點的這篇:RN元件架構設計:http://segmentfault.com/a/1190000004161358
設計React元件與設計一個jquery元件或者一個原生js元件最大的區別就是狀態的設計。
術語定義
-
屬性
-
泛指使用者在初始化元件時候可以傳給元件的
-
有些框架也叫options
-
是public的
-
在RN體系中,叫props,其中還包含了事件
-
-
事件
-
是public的
-
是function型別的
-
在RN體系中使用props來引用
-
-
介面
-
是public的
-
是function型別的
-
通過元件例項化之後的物件,可以進行呼叫
-
-
內部屬性
-
是private的
-
傳統設計方案中一般用於儲存元件的狀態,資料等
-
RN體系中沒有對其進行明確,可以自由設計
-
-
狀態
-
RN體系中明確提出的概念
-
傳統設計方案中一般使用內部屬性來表示
-
傳統設計思路
按照原來設計元件的方法論,一個UI元件對外應該具有屬性、事件、介面,對內具有內部屬性,內部介面。
-
屬性就像一份配置檔案,描述了元件應該具有的功能、外觀或者初始狀態。
-
事件是元件在工作工程中,當滿足某種條件的時候觸發的回撥函式
-
介面是元件物件的方法,可以讓元件去執行某個任務
在原來的設計理念中,並沒有提出元件狀態的概念,但是其也是一直存在的,通常是使用元件私有屬性來儲存。
比如,你設計一個按鈕,那麼他可能有正常狀態,禁用狀態,那麼我們會設計一個屬性disable={true|false}來通知元件初始化的具有的狀態,設計2個介面disable、enable來賦予js有動態改變其狀態的能力,設計2個事件onEnable、onDisable來通知回撥函式元件狀態發生了變化。虛擬碼如下:
//元件定義
class button{
constructor(disable,pid){//建構函式
this.disable=disable,//屬性:元件初始化使用這個作為狀態
this.pid=pid;//屬性:父容器的id
this._disable=null,//狀態:私有屬性
if(this.disable==true){//根據屬性來決定初始化狀態
this.disable();
}else{
this.enable();
}
this.render();//渲染元件
}
enable(){
this._disable=false;
if(this.el)this.el.set(`disable`,false);
this.fireEvent(`onEnable`);//觸發事件
}
disable(){
this._disable=true;
if(this.el)this.el.set(`disable`,true);
this.fireEvent(`onDisable`);//觸發事件
}
render(){
//渲染元件,狀態直接影響了元件的表現和功能
$(this.pid).innerHTML=`<button disable=`+this._disable+` />`;
//初始化對dom節點的引用
this.el=$(this.pid).getChild();
}
}
//父容器
<div id=`a`></div>
//例項化元件並使用
new button(false,`a`);
RN設計思路
上面的示例中,表示了一個傳統UI元件的設計思路,_disable就是這個button元件的關鍵狀態,它直接影響了元件的表現和行為。
而react架構直接把元件狀態提升到了一個新的高度,主要有以下幾點:
-
使用固定的介面來宣告元件狀態和狀態預設值
-
使用固定的介面來獲得和改變元件狀態的值
-
狀態的改變一定會改變元件的表現,會導致元件的重新渲染
前兩項都不是問題,因為我們原來也得有這些東西,只不過寫法發生了變化,關鍵是最後一項。這裡說的不是問題,指的是思路上比較容易接受。這種固定寫法,問題也很明顯,因為要想把一個狀態從RN狀態體系拿進拿出,會產生一定的工作成本,很是不爽。
我一直在思索,元件狀態的變化一定要導致view的變化嗎?
答案肯定是no,因為有些狀態僅僅影響元件的行為,並不影響表現。比如說,我賦予按鈕一個新功能,它可以提交某個表單的資料,也就是需要一個新的狀態formName,他就不影響表現,隻影響行為。
考慮到效能的極致,我們就只能把這種狀態放到RN的狀態體系之外,作為物件的私有屬性存在。
RN號稱diff演算法效能很高,但也不是0損耗,如果對RN的渲染理解很透徹,你當然也可以不這樣設計,但是我這裡還是傾向於保守一些,否則後期的調整也是有工作量的,因為定義、初始化、取值、改值這些操作程式碼都不一樣。寫到這裡我突然想到,如果可以,我們可以通過某種方法方便的修改某個狀態是否影響表現,不用改其它程式碼的話,那麼我們設計狀態的時候就不用區分了,就能讓我們更關注設計本身。
結論
說道這裡,基本可以理清思路了。
元件按照傳統方式設計,該怎麼設計就怎麼設計,在設計原來元件內部屬性的時候,多考慮一步,哪些內部屬性的改變是影響表現的,哪些內部屬性是不影響表現的。將影響表現的放入到RN狀態體系中,將不影響表現的,放入內部屬性中。即可。
tips
-
耦合性很強的父子元件,建議將狀態統一放到父元件中,子元件中不要放狀態了,無論是狀態的跨元件共享,還是對view渲染的觸發都很方便。除非你很確定某個狀態只子元件內部使用,通常這種情況後邊可能也會發生變化。
-
以下問題可以幫助識別是否是state,摘自官網
-
是否是從父級通過 props 傳入的?如果是,可能不是 state 。
-
是否會隨著時間改變?如果不是,可能不是 state 。
-
能根據元件中其它 state 資料或者 props 計算出來嗎?如果是,就不是 state 。
-
-
根據state的特點進行識別,加入到上一條
-
屬性的改變會影響到view的變化就可能是state
-
-
參考地址