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