react 單向數據流概念
'react框架是怎樣的數據流向?'||'react單向數據流是怎樣的概念 ?'
解答這個問題之前,我們首先得知道,js框架是個怎樣的概念。
框架:具備一定**編程思想**的(mvc/mvvm)js庫,叫做框架;
那么這道題的答案重點就在於編程思想這四個字上。
眾所周知,多數MVVM框架,如react、vue都是單向數據流的框架。
單向數據流:即規范了數據的流向——由外層組件向內層組件進行傳遞和更新。
其中,'傳遞'一詞應當是很容易被理解的,幾乎所有框架都是通過props往內層組件傳參(props本質是函數執行的參數);
然而,大家應該知道,復雜類型的數據(也就是對象)更新和簡單類型的數據更新是不一致的,舉個例子:
var a = {a:1}
var b = a;
b.a=2;
console.log(a) // {a:2}
而同樣的,我往一個函數內傳遞一個對象參數,如果在這個函數里修改了這個對象,那么函數外的對象也是會隨着改動的(因為本質是一個內存里的東西);
那么設想這樣的情景:我父組件的數據通過props傳遞給子組件,而子組件里更新了props,導致父組件更新——毫無疑問,這是會 導致數據紊亂的、不可控的操作。
因此絕大多數框架在這方面做了處理。
而react在這方面的處理,就是直接規定了(對組件而言,它的)props是只讀的,而不是可更改的;
想對而言,小程序和vue對props的限制上顯得更加自由——盡管它因此不得不做了其他限制。(此處不多做介紹,建議自己體驗下小程序原生開發或者vue開發)
ok,我們經由上述概念得知了單向數據流其實是一種框架本身對數據流向的限制。
那么為什么會做出這樣的限制呢? 為什么不讓我們為所欲為的想怎么傳就怎么傳呢?
react的編程思想和單向數據流的關系
針對上述問題,我們結合編程思想來思考這個問題的答案。
多數React框架的使用者可能在接觸react這門框架前,就聽說了有關react的諸如此類的評價——
”react,從入門到放棄。“
”相對vue,react入門難的一批。“
”react語法限制太嚴格。“
……
ok,首先在這里說些題外話——我要批判這類評價。理由很簡單:
在react基於es6改版之前,只要深層次掌握了原生js的構造函數,react入門難度其實也算不上啥。
1而在react16版本后,恕我直言,如果es6的class玩明白了,react上手使用真的零難度入門。
2jsx花五分鍾,如果之前接觸過ejs/xtemplate/jade這些模版引擎,jsx相對它們還要簡單;
3而props、state、refs、context,children可以看作幾個特殊的實例屬性(我們甚至可以直接做個推測:父類React.Component定義了它們的管理方式);
4那么封裝組件就是寫個子類啊沒毛病啊;
5好吧你說哪個框架沒有生命周期鈎子這玩意;
6高階組件對比一下類的修飾器(generetor,es6的提案,es7實現),我滴乖乖,一樣的東西啊;
綜上所述問題,react簡單的一批啊,我們只要在js的基礎上,學下jsx語法,弄明白幾個特殊實例屬性怎么玩,一張圖明白react的基本生命周期鈎子,結合單向數據流的思想,為所欲為啊。
……
跑遠了,我們回來講react編程思想和單向數據流之間的關系。
敲黑板了看重點:
react的編程思想是嚴謹且周密的,它約束了我們的花式操作,這是為了確保我們在使用react構建復雜項目的時候不會出現太多問題。
而好處也是顯而易見的——我們寫react項目,一旦出現了問題,那么我們會很輕松的發現,根源幾乎集中在props和state這倆實例屬性上。
單向數據流是react規范的數據流向,它的作用是極大的降低了我們組件間通信的代碼耦合,讓組件間的通信更為清晰,debug直接往props中找(后面會介紹context)。
也就是說,基於react嚴謹且周密的編程思想,制訂了單向數據流這樣的通信約束,使得我們react項目中的數據傳遞結構穩定且不易耦合,有事沒事找props解決一切通信問題(多好啊,你看vue不也樂呵呵的在使用嘛,話說這里好想吐個槽:很明顯了你們這些英語負八級的渣渣啊~找啥接口啊放棄react到vue,vue對比react最大優勢明明是中文文檔好啊有木有!畢竟是中國人做的啊!ps: 致敬尤大佬)。
單向數據流除了單向之外還有怎樣的限制?
其實react中的單向數據流,完整概念應該是: 數據的流向只能通過props由外層到內層 一層一層往里傳遞。
只能通過props一層一層往里傳遞這樣的限制啊……不可能的,考慮到項目復雜度,組件層級過高,這個我們真不能接受啊。
react想了想,是啊不能太狠毒,限制過大萬一沒人用豈不是尷尬了?於是加上了context這個玩意,方便我們進行組件間的隔代通信。
但react也是要面子的,完事還告訴我們:這玩意輕易不要用啊,危險啊這家伙,慎重使用啊小伙子們!
靠,君不見react-redux中的Provider組件,源碼就是簡單的用了context加上個插槽(children)就完事了啊…整個組件源碼就八九行啊,我閉着眼都能封裝給你看有木有啊喂!
所以說只要是放在正式版本中的api,我們都可以大膽的去使用,當然,前提是最好得知道它的核心原理甚至源碼的封裝,避免太花哨的操作引起不必要的八阿哥。
組件化的簡單實現
實則組件化也是最符合js編程者編程習慣的規范。這個要從組件的本質說起。
類組件的本質,是類,類的本質,是函數; 函數組件的本質也是函數。
那么,組件的本質=>函數。
是的,那么組件嵌套組件實例這種方式,像不像函數嵌套函數實例化對象?
可不就是嘛!我們思考下面的原生js代碼:
function child(props){
this.props = props
}
function parent(props){
this.props = props
this.state = '這是父函數的一個狀態'
this.childNodes = new child(this.state);
}
console.log(new parent('這是一個屬性'));
(別那么懶,f12一下,復制代碼到控制台里運行一下~)
運行以上代碼,你會發現——oh my god!
原來單向數據流通過props的實現不就這么點事嗎…(一臉懵b)當然不是啦,還有props的更新限制啊大哥們(其實就是深克隆,有興趣可以自己玩玩)
於是趕緊對比react的組件代碼:
class Child extends React.Component{
state = {
...this.props
},
render(){
return <div>我是Child組件</div>
}
}
class Parent extends React.Component{
state = {
data: '這是父組件的狀態'
},
render(){
console.log(this);
return <Child data = {this.state.data} />
}
}
//自己找個地方掛上
//ReactDOM.render( <Parent />, app);
簡單粗暴啊…不信你看看Vue和Angular,他們也在點頭啊…
寫在最后
就單向數據流的概念這個問題,在清晰的給出概念給面試官后,一定要結合react的嚴謹性去做個解釋,后面講講單向數據流的傳遞方式props和context,這道題基本已經不需要再講了。(你滿分了,別講了,再講你講講源碼吧)
然而,一般來講,在你講完單向數據流的概念后,心機的面試官立馬會問你下一個問題:
react既然規定了單向數據流, 那么如何在react中實現逆向通信?(子組件向父組件方向通信)
這個問題,我們留到下一篇做個講解。
(如果覺得本系列對您有幫助,請在下面評論里催更哦~)