web-dev-qa-db-ja.com

Reactネイティブモバイルアプリケーションをより高速にする方法は?

React Nativeモバイルアプリケーションは、クリックするたびに非常に遅くなります。反応ネイティブを使用していますv0.40.0および以下は、私のプロジェクトの依存関係です。

{
    "analytics-react-native": "^1.1.0",
    "apisauce": "^0.7.0",
    "babel-preset-es2015": "^6.18.0",
    "es6-promise": "^4.0.5",
    "flow-bin": "^0.36.0",
    "geolib": "^2.0.22",
    "immutable": "^3.8.1",
    "intl": "^1.2.5",
    "isomorphic-fetch": "^2.2.1",
    "lodash": "^4.17.4",
    "lodash.range": "^3.2.0",
    "prop-types": "^15.5.10",
    "raven-js": "^3.13.1",
    "react": "^15.4.2",
    "react-native": "^0.40.0",
    "react-native-Apple-healthkit-rn0.40": "^0.3.2",
    "react-native-blur": "^2.0.0",
    "react-native-button": "^1.7.1",
    "react-native-checkbox": "^2.0.0",
    "react-native-code-Push": "^1.17.3-beta",
    "react-native-datepicker": "^1.4.4",
    "react-native-device-info": "^0.10.1",
    "react-native-easy-toast": "^1.0.6",
    "react-native-fbsdk": "^0.5.0",
    "react-native-geocoder": "^0.4.5",
    "react-native-gifted-chat": "^0.1.3",
    "react-native-global-props": "^1.1.1",
    "react-native-image-crop-picker": "^0.15.1",
    "react-native-image-picker": "^0.25.1",
    "react-native-image-slider": "^1.1.5",
    "react-native-keyboard-aware-scroll-view": "^0.2.7",
    "react-native-maps": "0.15.2",
    "react-native-modal-dropdown": "^0.4.4",
    "react-native-popup-menu": "^0.7.2",
    "react-native-Push-notification": "^2.2.1",
    "react-native-radio-buttons": "^0.14.0",
    "react-native-router-flux": "3.38.0",
    "react-native-segmented-Android": "^1.0.4",
    "react-native-snap-carousel": "2.1.4",
    "react-native-stars": "^1.1.0",
    "react-native-swipeout": "^2.2.2",
    "react-native-swiper": "^1.5.4",
    "react-native-tableview-simple": "0.16.5",
    "react-native-vector-icons": "^4.0.0",
    "react-native-video": "^1.0.0",
    "react-native-zendesk-chat": "^0.2.1",
    "react-redux": "^4.4.6",
    "recompose": "^0.20.2",
    "redux": "^3.5.2",
    "redux-thunk": "^2.0.1"
  }

私はAndroid studiosでスタックトレースを使用してプロファイリングを行い、mqt_jsがすべてのUIクリックで時間がかかる原因の1つであることを発見しました。スタックトレースレポートをチェックしてください こちら

誰かがこのパフォーマンスの問題を解決するのを手伝ってくれますか?

14
Kishan Vaghela

まず、[〜#〜] debug [〜#〜]ではなくアプリを実行する必要があります。 Androidの場合、MainApplicationメソッドを変更することで実行できます。

_@Override
public boolean getUseDeveloperSupport() {
  return false; // BuildConfig.DEBUG;
}
_

そしてバンドルを作る:

_react-native bundle --platform Android --dev false --entry-file ./index.js --bundle-output ./Android/app/src/main/assets/index.Android.bundle --assets-dest ./Android/app/src/main/res/ --sourcemap-output ./Android/app/src/main/assets/index.Android.map
_

コードに関しては、最適化反応ネイティブのためのいくつかのアドバイスがあります:

  1. 解析とシリアル化(response.json()または_JSON.stringify_など)はjsスレッドをブロックするため、すべてのJSアニメーションとハンドラー(onScrollonPressなど)、およびもちろんrenderメソッド)これに悩まされます。表示する必要があるものだけをロードしてみてください。
  2. 可能な場合はネイティブアニメーション(_useNativeDriver: true_パラメータ)を使用し、onScrollは使用しないようにしてください。
  3. すべてのrenderメソッドをログに記録し、これらのメソッドの呼び出しをできる限り行わないようにしてください。コンポーネントの小道具または状態が変更されたときに呼び出されます。
  4. PureComponentの仕組みを理解し、必要に応じて使用してみてください。ただし、正しく使用しないと、アプリの速度が低下する可能性があることに注意してください。
  5. スタイルには常にStyleSheetを使用します。スタイルをキャッシュし、スタイルID(整数)に置き換えます。

悪い:

_// style object is created on every render
render() {
    return <View style={{flex:1}}/>
}
_

良い:

_render() {
    <View style={styles.flex}/>
}

// style is created once
const styles = StyleSheet.create({
    flex: { flex: 1 }
});
_
  1. 関数についても同じです。

悪い:

_// onPress handler is created on every render
render() {
    <TouchableOpacity onPress={() => this.props.navigator.navigate('SignIn')}/>
}
_

良い:

_render() {
    <TouchableOpacity onPress={this.onPressSignIn}/>
}

// onPressSignIn is created once
onPressSignIn = () => {
    this.props.navigator.navigate('SignIn');
}
_
  1. Big O クライアント上のすべての操作の定数は一定でなければなりません。できるだけ少ない配列を列挙します。可能であれば、常にObjectの代わりにSetArrayを使用してください。サーバー/データベースから大量のデータをロードする必要がある場合は、ページネーションを使用して、サーバーにソートやその他の重い計算を任せます。

たとえば、IDでオブジェクトを取得する必要がある場合は、次のように使用することをお勧めします。

_let items = {
    "123": { id: "123", ... },
    "224": { id: "224", ... }
};

let item = items["123"];
_

通常の配列の代わりに:

_let items = [
    0: { id: "123", ... },
    1: { id: "224", ... }
];

let item = items.find(x => x.id === "123");
_
8

これは非常に幅広いおよび意見に基づく質問ですが、私は_most common points_と、リストしたprofilerに基づく提案を強調表示してみてください。

スタックトレースを見ると、主な問題はパッケージ名の中の_UI Thread_、つまり_com.fitspot.app.debug_にあります。

前述のように ここ

フレームを表示するために、すべてのUI作業はその16ミリ秒の終わりまでに完了する必要があります。

境界間隔が_16ms_に設定されると、_mqt_js_または_JS Thread_が_16ms_よりも1サイクルではるかに長くかかっていることがわかります。つまり、_JS Thread )__は常に実行されています。

現在のprofilerでは、どのプロセスが_JS Thread_で実行されているかが不明であるため、問題は_JS Code_ではなく_UI Thread_に主にあることが明らかです。

_react-native_アプリを高速化する方法は複数あります。これについては、この page で詳しく説明されています。これはbasicGistと同じです。

  • エラーおよび警告メッセージはモード_dev=true_で提供されます。パフォーマンスを向上させるために、アプリ全体で無効にすることができます
  • JSスレッドで bottleneck が発生するため、アプリからすべての_console.log_ステートメントを削除します。このプラグインを使用して、次のように.babelrcファイル内の前述の_console*_ステートメントを削除できます here

    _{
      "env": {
      "production": {
      "plugins": ["transform-remove-console"]
      }
     }
    }
    _
  • プロジェクト構造をcomponentizeし、_Pure Components_を使用する必要があります。propsstateのみに依存するには、_immutable data structures_を使用して比較を高速化します。

  • _slower navigation transitions_の場合、_navigation library_のtimeoutがほとんどなので、_default transitions_コードを確認することをお勧めします。回避策として、独自のtransitionerを構築することを検討してください。

  • コードベースでAnimationsを使用している場合は、_nativeDriver=true_の設定を検討してください。これにより、_JS thread_の負荷が軽減されます。これはよく説明された です。

  • Profilingをチェックして、このページで詳しく説明されている_JS Thead_および_Main Thread_操作をチェックすることもできます。

  • 他のものには、_requiring/importing_ではないモジュールが含まれます。これは必要ありません。classesのみをインポートし、_whole component_はインポートしません。

  • また、_external libraries_のネイティブ要素よりもパフォーマンスが非常に遅いため、_simple UI components_を作成するのに_react-native_は必要ありません。 _styled-components_ を使用してUIをコンポーネント化することを検討できます

4
Pritish Vaidya
  1. Scrollviewで Flatlist を使用します。

    • 追加 initialNumToRender={number}フラットリストにプロップします。画面に表示されているコンポーネントのみを表示し、他のコンポーネントを切り離します。
  2. Flatlist renderItemで PureComponent を使用して(あなたの場合は、各カードになります)、小道具が変更されたときにのみレンダリングされるようにします。

  3. Render()またはComponentWillRecievePropsでコンソールをテストするためにコンポーネントが何度も再レンダリングされているかどうかを確認し、これが発生している場合はShouldComponentUpdateを使用します。

  4. Render()およびComponentWillRecievePropsからconsole.logを削除します。

これらの変更を行うと、パフォーマンスが以前よりもはるかに優れていることがわかります。

3
Rajat Gupta

反応ネイティブアプリを遅くするさまざまな理由が考えられます。役立つ次の重要なポイントを提案します。

  1. 可能な限りdumb componentsよりclass componentsを優先してください。
  2. reduxを使用してみてください。適切に実装されていれば、最高のコードを提供できる強力な状態管理ツールです。
  3. react-monocoleapprなどのツールを使用します。 react-monocole のガイド。
  4. 署名されたapkを生成します。デバッグされた反応ネイティブアプリには追加の機能があります。これが generate signed apk のガイドです。
2
madhav gaba

mqt_jsがパフォーマンスの問題の主な原因である場合、つまり、すべてのクリックで、アプリのJSスレッドが一度に実行できることが多すぎます。 JSビジネスロジックとアンダーレイネイティブレルム間の通信は非同期で行われ、ボタンが押されたときにJS側で完了する必要のあるアクションが多いほど、アプリの速度は低下します。

回答 Pritish Vaidyaによって与えられたものはすでに頭に釘を打ちます。アプリでのreduxの使用について、もう1つ説明します。アプリのデータフローが主にreduxを使用して行われている場合は、次のことを確認できます。

  • 各クリックイベントで発生しているreduxアクションが多すぎる場合は、不要なアクションを削除するか、重要なアニメーションをトリガーするアクションを優先してから、新しいRNコンポーネントのレンダリングが完了したら他のアクションをトリガーしてください。 redux-loggerを使用すると、どのアクションがボトムネックアクションであるかを確認できます。

  • Reduxのストアをリッスンするコンポーネントをより小さなものに分割し、それぞれがストアの異なる部分をリッスンします。したがって、reduxのストアが更新された場合、すべてではなく、コンポーネントの小さなグループのみを再レンダリングする必要があります。

  • メモ化されたセレクターを使用して、頻繁に更新されるデータを処理します。 reselect がこの場合に役立ちます。

1
blaz