ReactJS修煉之路(四):組件的性能優化及開發思路

少年,加油

昨天週五,那個喊我“少年”的朋友離職了去新加坡了,我的實習生涯又錯過了一位大神,不過短短一個月還是被影響不少,例如入坑happy hacking keybord同時學習各類軟件的快捷鍵,例如開始用sass,例如初次使用
flexbox

人生何處不相逢,謝謝你的指導,我會更加努力,也祝你更進一步,加油。


回看,事情總有千絲萬縷的聯繫,但是往前,都是迷霧,保持迷茫,保持思考,做好現在,是我最大的感悟。

之所以要說上面那些,是和這篇博客相關的,寫React也有半年多了,雖然都是零零散散地寫並沒有太多提高,但實踐總是好的,例如今天在做一個項目的首屏性能優化的時候,就頓悟了一些開發思路,感覺過去看到各種博客,與人交流的各種想法都零星地串聯了起來。

下面簡單分享一下我的組件優化思路及開發思路,不是最佳實踐,只是個人一些感觸。


緣由

昨晚開始看React後端渲染的內容,其實項目的第一版就是純後端渲染的,後來使用React-router改版成SPA,再後來進行了前後端分離,方便前端人員開發,因爲後臺是Rails,雖然也可以搞同構,不過支持rails的react-router版本太低(現在前端部分是webpack構建的),不好往回遷。

也想了一些方案,例如使用首屏後端模板渲染,同時加載前端資源,前端渲染完畢後替換首屏內容,實現起來不優雅,放棄了。

忽然想到,產品最重要的是體驗,說不定加載慢(2.5s)並不是體驗的最短板呢?

於是先不考慮後端渲染,但也做了一些微小的改進,後端頁面返回顯示loading效果(svg實現loading),前端渲染完成後,會有一個縮放漸現的過程,整體體驗還不錯,gif製造幀率低看着效果一般,在手機上超讚,安卓手機SVG動畫有點卡,待調研解決。
web app首頁加載效果

在拿不同手機測試這個首屏加載效果的時候,無意中發現,這個web應用首屏操作不夠流暢,於是就甩開手上的6s,借了舍友淘汰下來安卓機做測試,真是卡到不行。

忽然覺得前端工程師就應該用落後兩年左右的手機,這樣才能真正確保產品質量。(開個玩笑,別在意)


優化思路

最近在網上看到一份谷歌的web app開發教程,內容比較多,還沒看完,所以還不知道怎麼評測性能,目前最直觀的就是,加載速度(白屏時間),操作流暢度。

我的思路很簡單,也很有效,直接在各個組件的render函數裏console.log("xxx render")到控制檯,觀察每個組件的渲染次數,減少不必要的渲染。

下面總結一下,什麼情況下會出現不必要的render,怎麼減少。

  1. 父組件裏面的子組件排序引起子組件render,其實這個時候子組件的內容是沒有任何改變的,只是子組件所在的位置改變而已,按理說子組件是不需要render的。解決方法:shouldComponentUpdate,判斷內容不變就跳過更新,如果內容是一直不變的,推薦直接return false,省去判斷的成本。

  2. 有些組件會先加載,再異步請求數據,再重新渲染,會出現兩次render(不推薦這種做法,下文將開發思路會講到),解決方案,在render函數裏面進行判斷,如果沒有數據,直接return <div>沒有數據時候的提示信息</div>

還有一個小小的點:

  • React組件render很頻繁,所以render函數裏面儘量減少操作,例如:
//每次都會循環生成相同的內容,性能差
<div className="swiper-pagination">
{
  [1,2,3].map( function(i) {
    return <span className="swiper-pagination-bullet"></span>
  } )
}
</div>

//性能要好一些
<div className="swiper-pagination">
  <span className="swiper-pagination-bullet"></span>
  <span className="swiper-pagination-bullet"></span>
  <span className="swiper-pagination-bullet"></span>
</div>

上面只提到了兩種情況和方案,把這兩個做好性能應該不是大的問題了,總之,核心還是,找到不必要的render,儘量避免


開發思路

simple is the best.

正因爲做性能優化纔有了組件開發思路的感悟和改進,真覺得以前是隨便亂寫,哈哈,不過厲害的地方在於,隨便亂寫的代碼竟然能運行,但人終歸要成長,標準也在提高。

說開發思路之前,有空的同學先去溫習React組件生命週期,這個非常重要。

之前看過一段時間Redux,對於裏面的容器組件和展示組件並不是太瞭解,然而今天好像有點能體會什麼是容器組件和展示組件了,簡而言之,展示組件只做展示,容器組件封裝了數據獲取和數據操作的邏輯(沒有上手redux,望指正)

下面直接上展示組件的代碼(舊的react代碼風格,別吐槽):

var component = React.createClass({
  getInitialState: function() {
    //狀態初始化(第一輪執行)
    //可用於類型檢查
  },
  componentDidMount: function() {
    //組件加載完成執行的動作(第一輪執行)
  },
  componentWillReceiveProps: function(nextProps) {
    //props更新,用於設置state(第二輪開始執行)
    //注意,這裏setState並不會引發新的一輪更新
  },
  shouldComponentUpdate: function() {
    //決定組件是否更新(第二輪開始執行)
    return false/true;
  },
  render: function() {
    //渲染內容
    console.log("render");
  }
});

上面幾個生命週期函數擺放的位置是特意調整的,現在我們來走一遍流程,父組件通過設置子組件的props傳遞數據,此時組件調用getInitialState,初始化狀態,然後組件執行render完成渲染,展示組件就是那麼簡單,到這裏只是渲染了一次,這個時候,父組件要是再次render,會影響到子組件,子組件會調用componentWillReceiveProps來更新組件狀態,再調用shouldComponentUpdate來確定是否跳過render。遵循這個開發思路不僅能使開發的時候保持清晰的邏輯,也在開發的時候保證了組件的性能,不用想我上面那樣修修補補。


總結

  • 多看官博,瞭解核心思想
  • 多寫代碼,不止於demo,去寫項目,去解決問題

以前總喜歡問別人最佳實踐,後來發現,如果你去問別人,那別人告訴你多半也聽得一知半解。

規劃重要,實踐也重要,最重要的是在已有前提下想辦法做到自己想要的效果,而不是抱怨自己當初沒考慮周全,生活也是如此。

寫碼路上沒有捷徑,去創造,去超越,少年。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章