React Native 性能優化 (官網指南搬運)

最近在寫React-Native 趁着這兩天需求差很少完成了,實踐了一些優化項。javascript

記錄於此html

Life sucks

Performancejava

參考 React native Performancereact

查看性能

打開開發者菜單(搖晃手機打開)👉 打開Show Perf Monitor 能夠看到下圖顯示框git

img

UI 和 JS 的幀數都穩定保持在60 爲最優狀況。github

JS 的單線程

全部的事件處理,API請求,等操做都在這個線程上,在this.setState大量數據時,狀態的變更會致使re-render,這期間全部由JavaScript 控制的動畫都會出現卡頓掉幀npm

好比在切換路由時,幀數會有明顯抖動。此時若是有一些在componentDidMount 執行的操做就會使得路由過渡動畫很是卡頓。(後面會介紹一些能夠嘗試的解決方案json

開發環境性能比生產環境差

開發環境下框架會有不少別的操做好比warning error 的輸出,類型檢測等等。react-native

若是要測試性能,最好在release 包測試。這樣更加精準。數組

生產環境移除console.*

開發時,會有不少console.* 指令來幫助調試。而且一些依賴庫也會有console.* 這些語句對JavaScript 線程來講是一個極大的消耗。能夠經過Babel 在生產環境中移除掉console.*

  • 安裝插件

    npm i babel-plugin-transform-remove-console --save-dev

  • 配置.babelrc 文件

    {
      "env": {
        "production": {
          "plugins": ["transform-remove-console"]
        }
      }
    }

處理大量數據列表時使用<FlatList />

FlatList 組件更加適合來展現長列表,而且指定合適的 getItemLayout 方法, getItemLayout 會跳過渲染Item 時的佈局計算,直接使用給定的配置(詳情查看連接☝️)

依賴懶加載

在框架執行編寫好的業務代碼前,須要把在內存中加載並解析代碼,代碼量越大這個過程就更耗時,致使首屏渲染速度過慢。並且每每會出現一些頁面或者組件根本不會被用戶訪問到。這時能夠經過懶加載來優化。

官網有給出例子

VeryExpensive.js

import React, { Component } from 'react';
import { Text } from 'react-native';
// ... import some very expensive modules

// You may want to log at the file level to verify when this is happening
console.log('VeryExpensive component loaded');

export default class VeryExpensive extends Component {
  // lots and lots of code
  render() {
    return <Text>Very Expensive Component</Text>;
  }
}

Optimized.js

import React, { Component } from 'react';
import { TouchableOpacity, View, Text } from 'react-native';

let VeryExpensive = null; //定義變量

export default class Optimized extends Component {
  state = { needsExpensive: false }; // 定義內部狀態來控制組件是否須要加載

  didPress = () => {
    // 在觸發須要加載組件的事件時
    if (VeryExpensive == null) { // 不重複引用
      VeryExpensive = require('./VeryExpensive').default;  // 把組件的引用賦給定義好的變量
    }

    this.setState(() => ({
      needsExpensive: true, // 更改控制的狀態,觸發組件re-render
    }));
  };

  render() {
    return (
      <View style={{ marginTop: 20 }}>
        <TouchableOpacity onPress={this.didPress}>
          <Text>Load</Text>
        </TouchableOpacity>
        {this.state.needsExpensive ? <VeryExpensive /> : null}
      </View>
    );
  }
}

優化組件渲染次數

React 在內部state 或者外部傳入的props 發生改變時,會從新渲染組件。若是在短期內有大量的組件要從新渲染就會形成嚴重的性能問題。這裏有一個能夠優化的點。

  • 使用PureComponent 讓組件本身比較props 的變化來控制渲染次數,實踐下來這種可控的方式比純函數組件要靠譜。或者在Component 中使用 shouldComponentUpdate 方法,經過條件判斷來控制組件的更新/從新渲染。
  • 使用PureComponent 時要注意這個組件內部是淺比較狀態,若是props 的有大量引用類型對象,則這些對象的內部變化不會被比較出來。因此在編寫代碼時儘可能避免複雜的數據結構
  • 細粒度組件,拆分動態/靜態組件。須要在項目穩定並有必定規模後來統一規劃。
  • 學習 immutable-js

異步,回調

JavaScript 單線程,要利用好它的異步特性,和一些鉤子回調。

好比上面提到路由切換時componentDidMount 中的操做會致使卡頓,這裏可使用 InteractionManager.runAfterInteractions() 將須要執行的操做放到runAfterInteractions 的回調中執行。

componentDidMount() {
    InteractionManager.runAfterInteractions(() => {
        // your actions
    })
}

須要注意的是 InteractionManager 是監聽全部的動畫/交互 完成以後纔會觸發 runAfterInteractions 中的回調,若是項目中有一些長時間動畫或者交互,可能會出現長時間等待。因此 因爲 InteractionManager 的不可控性,使用的時候要根據實際狀況調整。

在react-native 中的一些動畫反饋,好比TouchableOpacity 在觸摸時會響應 onPress 而且 自身的透明度會發生變化,這個過程當中若是 onPress 中有複雜的操做,極可能會致使組件的透明反饋卡頓,這時能夠將onPress 中的操做包裹在 requestAnimationFrame 中。這裏給出一個個人實踐(利用styled-component)

import styled from 'styled-components'

export const TouchableOpacity = styled.TouchableOpacity.attrs({
  onPress: props => () => {
    requestAnimationFrame(() => {
      props.onPressAsync && props.onPressAsync()
    }, 0)
  }
})``

這裏把onPress 改爲在 requestAnimationFrame 的回調中執行onPressAsync 傳入的操做。

同理,還在FlatListonReachEnd實踐了這個操做,來避免iOS 中滾動回彈時執行操做的卡頓。

以上,記錄了近期寫React-Native 的一些實踐過的優化項。

最後

路漫漫其修遠兮,吾將上下而求索

May love & peace be with you

參考

本文做者: Roy Luo

本文連接: React Native 性能優化 (官網指南搬運)

相關文章
相關標籤/搜索