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