摘要:父組件向子組件之間非常常見(jiàn),通過(guò)機(jī)制傳遞即可。我們應(yīng)該聽(tīng)說(shuō)過(guò)高階函數(shù),這種函數(shù)接受函數(shù)作為輸入,或者是輸出一個(gè)函數(shù),比如以及等函數(shù)。在傳遞數(shù)據(jù)的時(shí)候,我們可以用進(jìn)一步提高性能。
本文主要談自己在react學(xué)習(xí)的過(guò)程中總結(jié)出來(lái)的一些經(jīng)驗(yàn)和資源,內(nèi)容邏輯參考了“深入react技術(shù)棧”一書以及網(wǎng)上的諸多資源,但也并非完全照抄,代碼基本都是自己實(shí)踐,主要為平時(shí)個(gè)人學(xué)習(xí)做一個(gè)總結(jié)和參考。
本文的關(guān)鍵內(nèi)容:樣式處理與css模塊化、組件間通信(非flux架構(gòu))、組件抽象、組件性能優(yōu)化以及React 動(dòng)畫五種內(nèi)容。
1.樣式處理與css模塊化在react出現(xiàn)之前,我們寫樣式一般是將css分離的,并且用less/sass預(yù)處理器,我個(gè)人在用backbone等MV*框架的時(shí)候就習(xí)慣用less并且用nodejs配置一個(gè)模塊用來(lái)編譯less。
但這樣寫會(huì)有一些問(wèn)題:
命名沖突是一個(gè)很常見(jiàn)的問(wèn)題,因此,我們要制定出一套自己的完整命名規(guī)范來(lái),并且要防止和項(xiàng)目中引入的庫(kù)出現(xiàn)沖突。
充分利用優(yōu)先級(jí)是一個(gè)比較好的實(shí)踐,但是這樣寫出的less代碼有點(diǎn)像回調(diào)函數(shù)塔,雖然我本人并不覺(jué)得這有什么不好甚至還比較享受這種編程,但這的確不利于充分壓縮css代碼。
于是我們引入css modules。
簡(jiǎn)單的說(shuō),如果我們配置了css modules的話,那么你在css中寫的類名和你在組件中寫的class = ...都會(huì)被重新編譯成一個(gè)哈希字符串,這樣我們就不用考慮命名沖突的問(wèn)題了,另外也可以比較自由的在local和global的css變量之間切換(實(shí)際上,這樣的css變量默認(rèn)都是local的,如果需要global,我們需要:global前綴,這樣的話css變量就不會(huì)被轉(zhuǎn)化成特殊的哈希值了)
需要注意的是寫法問(wèn)題,這個(gè)時(shí)候我們就不能在jsx中僅僅用className了,css module實(shí)際上限制了我們必須要用className={style.title}這樣的寫法,實(shí)際上我在嘗試的時(shí)候因?yàn)檫@個(gè)地方的bug調(diào)試了很久,而這也在某一種程度上給利用css module進(jìn)行重構(gòu)代碼帶來(lái)了一些困難。
關(guān)于css modules的入門介紹,沒(méi)錯(cuò),阮一峰老師寫了一份:http://www.ruanyifeng.com/blo...
另外,有的同學(xué)認(rèn)為css modules并不夠優(yōu)雅,實(shí)際上上文的寫法限定的問(wèn)題就是一個(gè)麻煩事,所以我們可以用react-css-modules庫(kù),這個(gè)庫(kù)解決了css modules的一些不是很好的問(wèn)題,因?yàn)樯鲜植⒉浑y,這里不詳細(xì)介紹了(可以參考這里以及“深入react技術(shù)棧”73頁(yè))
2.組件間通信(非flux架構(gòu))接下來(lái)我們總結(jié)一下react組件間通信的幾種方式,雖然現(xiàn)在有了redux等最佳實(shí)踐,但是很多時(shí)候我們還是需要原生可用的組件通信機(jī)制。
非常常見(jiàn),通過(guò)props機(jī)制傳遞即可。
利用回調(diào)函數(shù),回調(diào)函數(shù)本身定義在父組件中,通過(guò)props方式傳遞給子組件,在子組件中調(diào)用回調(diào)函數(shù)。
利用自定義事件機(jī)制,這種方法更通用方便,并且可以簡(jiǎn)化API,關(guān)于自定義事件機(jī)制的詳細(xì)使用方法我們?cè)诮酉聛?lái)展開(kāi)。
context機(jī)制。不過(guò)這種機(jī)制react并不是特別推薦(不是特別推薦并不代表會(huì)在將來(lái)的版本沒(méi)有,只是說(shuō)明可能會(huì)產(chǎn)生一定的弊端因此要慎用少用),context機(jī)制需要在上級(jí)組件(可以是父組件的父組件)定義一個(gè)getChildContext函數(shù)如下:
getChildContext(){ return{ color:"red", } }
當(dāng)然也可以用事件機(jī)制
這回只能用事件機(jī)制了,雖然我之前分析過(guò)別的框架的事件機(jī)制部分都可以多帶帶拎出來(lái)用,但是這里面實(shí)際上有好多方式。
我首先試了一下js-signals這個(gè)庫(kù),這個(gè)也是React團(tuán)隊(duì)使用的,用起來(lái)也還簡(jiǎn)單,npm install signals之后,我們可以多帶帶寫一個(gè)Signal文件:
const signals= require("signals"); var Signal = { started : new signals.Signal() };
我們可以把接收事件的函數(shù)定義在組件B中:
onStarted(param1, param2){ alert(param1 + param2); } constructor(props){ super(props); Signal.started.add(this.onStarted); //add listener }
然后在組件A中(注意dispatch的時(shí)候要保證B已經(jīng)被構(gòu)造出來(lái)了):
handlethis () { Signal.started.dispatch("foo", "bar"); //dispatch signal passing custom parameters } render(){ return ( ) }
其實(shí)還有很多類似的組件,當(dāng)然我們自己寫一個(gè)功能弱的也不成問(wèn)題,更多的方式,這篇文章介紹的不錯(cuò)。
3.組件抽象 mixinmixin是一個(gè)飽受詬病的東西,另外蛋疼的是在ES6的寫法下也不能用,筆者現(xiàn)在寫react的時(shí)候都已經(jīng)不用了,所以這里進(jìn)行簡(jiǎn)單介紹。
我們可以通過(guò)在createClass的時(shí)候傳入一個(gè)mixins數(shù)組,這個(gè)數(shù)組里是我們的一些通用的方法:
React.createClass({ mixins:[method1,method2] //... })
這在ES6的class形式下是不能“直接”使用的。
ES7 decorator 與 mixinES7 的 decorator,作用就是返回一個(gè)新的 descriptor,并把這個(gè)新返回的 descriptor 應(yīng)用到目標(biāo)方法上。稍后我們將會(huì)看到,decorator 并非只能作用到類的方法/屬性上,它還可以作用到類本身。
當(dāng)然,這個(gè)我只言片語(yǔ)肯定說(shuō)不明白的,這個(gè)我要推薦淘寶前端團(tuán)隊(duì)的這篇文章。
另外,core-decorators這個(gè)庫(kù)值得關(guān)注,它里面有一個(gè)mixin方法用于實(shí)現(xiàn)mixin,原理就是用了ES7 decorator,實(shí)現(xiàn)起來(lái)也不是非常復(fù)雜。
最后,提醒一下ES7 decorator雖然很酷,但是目前還處于提案階段,雖然借助babel我們已經(jīng)可以體驗(yàn)了,但是距離真正支持還有一段距離
高階組件(HOC)這是一個(gè)頗值得一提的話題。
我們應(yīng)該聽(tīng)說(shuō)過(guò)高階函數(shù),這種函數(shù)接受函數(shù)作為輸入,或者是輸出一個(gè)函數(shù),比如map、reduce以及sort等函數(shù)。
一個(gè)高階組件只是一個(gè)包裝了另外一個(gè) React 組件的 React 組件, 這種包裝通常有兩種方式:
1、屬性代理(Props Proxy):高階組件操控傳遞給 WrappedComponent 的 props,
2、反向繼承(Inheritance Inversion):高階組件繼承(extends)WrappedComponent。
高階組件的功能主要有以下幾點(diǎn):
1、代碼復(fù)用,邏輯抽象,抽離底層準(zhǔn)備(bootstrap)代碼
2、渲染劫持
渲染劫持主要通過(guò)反向繼承來(lái)實(shí)現(xiàn),我們可以選擇是否渲染原組件,也可以改變?cè)M件的渲染結(jié)果(注意:我們通過(guò) var elementsTree = super.render()可以拿到原組件的渲染結(jié)果,然后我們可以改變props之后,通過(guò)原生cloneElement方法創(chuàng)建出新的節(jié)點(diǎn)樹(shù))
3、State 抽象和更改
所謂抽象state的目的,就是將原組件作為一個(gè)純粹的展示型組件,分離內(nèi)部狀態(tài),將state交給高階組件來(lái)控制。比如:我們可以抽象出一個(gè)控制input的高階組件,從而不用在input中來(lái)有很多控制state的代碼。
4、Props 更改
我們可以讀取、增加、編輯、刪除被包裹組件的props
我在這里沒(méi)有給出代碼,為了避免文章過(guò)于冗長(zhǎng)以及和網(wǎng)上其他專題文章大部分重復(fù),我主要是進(jìn)行一些總結(jié),具體內(nèi)容我這里仍然是推薦一篇文章
4.組件性能優(yōu)化 PureRenderPureRender這個(gè)概念實(shí)際上和純函數(shù)有關(guān),Pure指的是對(duì)同樣的輸入(對(duì)于react來(lái)說(shuō)就是props和state)總是得到相同的輸出,針對(duì)這個(gè)問(wèn)題,React有一個(gè)shouldComponentUpdate鉤子,這個(gè)鉤子默認(rèn)返回true,用于props或者state改變或者接收到新的值時(shí)候,可以供用戶重寫,這樣在接受到相同的props的時(shí)候我們就可以防止其重新渲染。
PureRenderMixin在這個(gè)時(shí)候要派上用場(chǎng)了,這是一個(gè)能夠?qū)崿F(xiàn)上述功能的官方插件,react是這樣介紹它的:
If your React component"s render function renders the same result given the same props and state, you can use this mixin for a performance boost in some cases.
實(shí)際上是通過(guò)一個(gè)淺比較來(lái)確定是不是該被渲染,這實(shí)際上是一個(gè)性能上的權(quán)衡和妥協(xié),深比較真的是耗費(fèi)太多(我們?cè)谙乱还?jié)會(huì)提出一個(gè)更好的解決方案)。
寫法也比較簡(jiǎn)單:
import PureRenderMixin from "react-addons-pure-render-mixin"; class FooComponent extends React.Component { constructor(props) { super(props); this.shouldComponentUpdate = PureRenderMixin.shouldComponentUpdate.bind(this); } render() { returnfoo; } }
我們可以在這里查看更多信息。
Immutable.js在傳遞數(shù)據(jù)的時(shí)候,我們可以用Immutable Data進(jìn)一步提高性能。
Immutable.js定義了不可變對(duì)象,一個(gè)數(shù)據(jù)結(jié)構(gòu)(MapListArraySet)一旦被定義,就不可變了,我們把它如果用于state,那么每次變化的時(shí)候需要將state整個(gè)重新賦值。
上文提到,在shouldComponentUpdate使用PureRenderMixin由于性能權(quán)衡我們只能使用淺比較,但是如果我們用了Immutable.js,我們有更好的方式:直接用=== or is就可以判斷,因?yàn)镮mmutable.js比較的是兩個(gè)對(duì)象的hashCode或者valueOf,并且內(nèi)部使用了trie數(shù)據(jù)結(jié)構(gòu)(比如字典樹(shù))來(lái)存儲(chǔ),因此性能很高。
另外,由于Immutable.js中提供的數(shù)據(jù)結(jié)構(gòu)是不可變的,我們不用擔(dān)心js中源對(duì)象跟隨引用對(duì)象的變化而變化的問(wèn)題,也不用考慮函數(shù)中所謂的引用賦值,這給我們的編程帶來(lái)了很多方便。
當(dāng)然也有不方便的是Immutable.js的數(shù)據(jù)結(jié)構(gòu)并不能和原生的數(shù)據(jù)結(jié)構(gòu)混用,因此寫法上需要格外注意,關(guān)于更多資料請(qǐng)看這里.
無(wú)狀態(tài)組件生命周期讓react的組件變得功能非常強(qiáng)大并且復(fù)雜,從而難以維護(hù),而有的時(shí)候我們又要經(jīng)常寫一些自身沒(méi)有狀態(tài),只從父組件接受props的組件,這種組件可以提高react的渲染性能,也被官方推薦。
const HelloWorld = (props) =>{props.name}ReactDOM.render(,App)
簡(jiǎn)單,高效,在有些不需要改變的地方,比如沒(méi)有用戶交互純聲明性質(zhì)的內(nèi)容,可以用無(wú)狀態(tài)組件。
react的diff算法我們想要讓效率更高,還要注意的一點(diǎn)就是要照顧react的diff算法,react雖然有一個(gè)復(fù)雜度僅為O(N)的diff算法,但是這個(gè)算法也不是萬(wàn)能的,我們要想讓react效能最大化,就要去照顧這個(gè)diff算法。
總的說(shuō)來(lái),這個(gè)diff算法大概有三點(diǎn)實(shí)現(xiàn)概要:
對(duì)兩棵樹(shù)進(jìn)行比較,react認(rèn)為,對(duì)節(jié)點(diǎn)的跨層級(jí)操作移動(dòng)較少,所以只會(huì)對(duì)相同層級(jí)的dom節(jié)點(diǎn)進(jìn)行比較,即同一個(gè)父節(jié)點(diǎn)下的字節(jié)點(diǎn),當(dāng)發(fā)現(xiàn)節(jié)點(diǎn)已經(jīng)不存在時(shí),就會(huì)刪除節(jié)點(diǎn),當(dāng)發(fā)現(xiàn)節(jié)點(diǎn)新增時(shí)候,就會(huì)插入節(jié)點(diǎn)。
為了迎合這個(gè)策略,我們盡量不要對(duì)dom節(jié)點(diǎn)進(jìn)行跨層級(jí)操作(比如把某一個(gè)字節(jié)點(diǎn)轉(zhuǎn)而掛在到某一個(gè)孫節(jié)點(diǎn)下面),因?yàn)檫@樣效率是比較低的。
對(duì)組件之間進(jìn)行比較:如果是同一個(gè)類型的組件,按照第一條策略進(jìn)一步比較虛擬dom樹(shù);如果不是,就將該組件判斷為dirty,從而替換所有字節(jié)點(diǎn);對(duì)于同一類型的組件,有可能其虛擬dom樹(shù)沒(méi)有發(fā)生變化,如果能夠確切知道這一點(diǎn),那么就可以節(jié)省大量diff的操作時(shí)間,因此,react允許用戶通過(guò)shouldComponentUpdate鉤子來(lái)判斷組件是否發(fā)生變化。
為了迎合這個(gè)策略,我們可以使用上面提到的PureRender或者Immutable.js。
當(dāng)節(jié)點(diǎn)處于同一個(gè)層級(jí),react提供了插入、移動(dòng)、刪除操作,這里主要指相似節(jié)點(diǎn),比如
為了迎合這一規(guī)則,我們要給li標(biāo)簽等添加一個(gè)key(實(shí)際上已經(jīng)被react強(qiáng)制),另外,在開(kāi)發(fā)過(guò)程中盡量減少將最后一個(gè)節(jié)點(diǎn)移動(dòng)到第一個(gè)的情況,因?yàn)檫@個(gè)時(shí)候react要進(jìn)行很多的移動(dòng)操作。
5.React 動(dòng)畫 緩動(dòng)函數(shù)對(duì)于各種動(dòng)畫來(lái)說(shuō),緩動(dòng)體驗(yàn)一般是:linear < ease淡入淡出 < spring彈性動(dòng)畫cubic bezier貝塞爾曲線。
動(dòng)畫的方式有css動(dòng)畫和js動(dòng)畫,但是很多時(shí)候我們都是一起用的,所以區(qū)分的太詳細(xì)似乎必要性也不大。
成熟的動(dòng)畫庫(kù)實(shí)際上動(dòng)畫經(jīng)常是筆者比較忽視的一個(gè)方面,由于還沒(méi)畢業(yè),大多時(shí)候都是自己做小東西,最后動(dòng)畫就成了可有可無(wú)的環(huán)節(jié),另外現(xiàn)在的各種動(dòng)畫庫(kù)很多,方便到只需要一個(gè)class、只寫一行代碼就可以做出相對(duì)過(guò)得去的效果,自己也就疏于探索。
這部分內(nèi)容主要推薦一些成熟的動(dòng)畫庫(kù)。
首先是ReactCSSTransitionGroup,這個(gè)動(dòng)畫庫(kù)提供了一些生命周期鉤子,我們可以利用此加動(dòng)畫,具體學(xué)API的過(guò)程相當(dāng)簡(jiǎn)單,我相信看懂上面各個(gè)部分的同學(xué)直接按照給出的鏈接肯定能順利學(xué)會(huì)。
還有react-smooth動(dòng)畫庫(kù),這也是一個(gè)比較有意思的動(dòng)畫庫(kù),寫法類似css的多關(guān)鍵幀動(dòng)畫。并且?guī)追N緩動(dòng)函數(shù)動(dòng)畫這里都能實(shí)現(xiàn)。
react-motion也是一個(gè)值得推薦的動(dòng)畫庫(kù),如果想用spring動(dòng)畫這個(gè)似乎是更好的選擇。
另外,不說(shuō)react,還有一個(gè)讓我印象深刻不得不提的就是vivus.js這個(gè)svg動(dòng)畫庫(kù),不得不說(shuō)真是酷斃了。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/81507.html
摘要:父組件向子組件之間非常常見(jiàn),通過(guò)機(jī)制傳遞即可。我們應(yīng)該聽(tīng)說(shuō)過(guò)高階函數(shù),這種函數(shù)接受函數(shù)作為輸入,或者是輸出一個(gè)函數(shù),比如以及等函數(shù)。在傳遞數(shù)據(jù)的時(shí)候,我們可以用進(jìn)一步提高性能。 本文主要談自己在react學(xué)習(xí)的過(guò)程中總結(jié)出來(lái)的一些經(jīng)驗(yàn)和資源,內(nèi)容邏輯參考了深入react技術(shù)棧一書以及網(wǎng)上的諸多資源,但也并非完全照抄,代碼基本都是自己實(shí)踐,主要為平時(shí)個(gè)人學(xué)習(xí)做一個(gè)總結(jié)和參考。 本文的關(guān)鍵...
摘要:父組件向子組件之間非常常見(jiàn),通過(guò)機(jī)制傳遞即可。我們應(yīng)該聽(tīng)說(shuō)過(guò)高階函數(shù),這種函數(shù)接受函數(shù)作為輸入,或者是輸出一個(gè)函數(shù),比如以及等函數(shù)。在傳遞數(shù)據(jù)的時(shí)候,我們可以用進(jìn)一步提高性能。 本文主要談自己在react學(xué)習(xí)的過(guò)程中總結(jié)出來(lái)的一些經(jīng)驗(yàn)和資源,內(nèi)容邏輯參考了深入react技術(shù)棧一書以及網(wǎng)上的諸多資源,但也并非完全照抄,代碼基本都是自己實(shí)踐,主要為平時(shí)個(gè)人學(xué)習(xí)做一個(gè)總結(jié)和參考。 本文的關(guān)鍵...
摘要:前言接下來(lái)讓我們進(jìn)入新的章節(jié)漫談。正文一事件系統(tǒng)的事件系統(tǒng)事件系統(tǒng)符合標(biāo)準(zhǔn),不存在任何兼容性問(wèn)題,并且與原生的瀏覽器事件一樣有同樣的接口。所有的事件都自動(dòng)綁定到最外層。組織事件冒泡的行為只適用于合成系統(tǒng)中,且沒(méi)辦法阻止原生事件冒泡。 前言 接下來(lái)讓我們進(jìn)入新的章節(jié):漫談React。本篇文章主要講React事件系統(tǒng)和表單操作。 正文 一:事件系統(tǒng) 1.react的事件系統(tǒng)react事件系...
摘要:前端日?qǐng)?bào)精選低成本將你的網(wǎng)站切換為漫談組件庫(kù)開(kāi)發(fā)一多層嵌套彈層組件可作的備胎深入理解進(jìn)階系列如何設(shè)計(jì)中文刷題系列前端筆試面試題知乎專欄個(gè)拯救前端開(kāi)發(fā)者的工具庫(kù)和資源眾成翻譯前端技術(shù)大會(huì)震撼登陸,明星團(tuán)隊(duì)講師傾城而出前端組件庫(kù)我們做 2017-09-08 前端日?qǐng)?bào) 精選 低成本將你的網(wǎng)站切換為 HTTPS漫談 React 組件庫(kù)開(kāi)發(fā)(一):多層嵌套彈層組件Preact: 可作React的...
摘要:引言組件中有很多彈出式組件,常見(jiàn)的如,以及等。這樣一種層次結(jié)構(gòu)在實(shí)踐中大大降低了各類彈層組件的實(shí)現(xiàn)和維護(hù)成本。但是的組件實(shí)現(xiàn)了一個(gè)大多數(shù)組件庫(kù)都沒(méi)有實(shí)現(xiàn)的功能彈層的嵌套處理。 引言 UI 組件中有很多彈出式組件,常見(jiàn)的如 Dialog,Tooltip 以及 Select 等。這些組件都有一個(gè)特點(diǎn),它們的彈出層通常不是渲染在當(dāng)前的 DOM 樹(shù)中,而是直接插入在 body (或者其它類似的...
閱讀 1847·2021-11-25 09:43
閱讀 3688·2021-11-24 10:32
閱讀 1076·2021-10-13 09:39
閱讀 2328·2021-09-10 11:24
閱讀 3344·2021-07-25 21:37
閱讀 3464·2019-08-30 15:56
閱讀 858·2019-08-30 15:44
閱讀 1449·2019-08-30 13:18