React Nativeパフォーマンス最適化のポイントまとめ

React Nativeでパフォーマンスを向上するためのポイントについてまとめました。

## ScrollViewではなく、FlatListを使用
　表示するデータ量が多い場合は、`ScrollView`ではなく`FlatList`を使用しましょう。

　`ScrollView`は一度に全ての子コンポーネントをレンダリングします。見えていない箇所の子コンポーネントとレンダリングされるためメモリ使用量が増えます。

#### ScrollViewでの実装

```jsx
const data = [
  {
    text: "1",
  },
  {
    text: "2",
  },
]

const App = () => (
  <ScrollView>
    {data.map((_) => (
      <Text>{_}</Text>
    ))}
  </ScrollView>
)
```


　一方、`FlatList`は画面に見えている箇所のみレンダリングし、画面から見えなくなるとレンダリングを止めます。メモリ使用量を抑えるには、`ScrollView`より`FlatList`が良いと言えます。

```jsx
const data = [
  {
    text: "1",
  },
  {
    text: "2",
  },
]

const App = () => (
  <FlatList
    data={data} 
    renderItem={({ item }) => (
      <Text>{item.text}</Text>
    )}
  />
)
```

## 本番環境でconsole.*を実行させない
　`console.log`や`console.warn`はデバッグに用いることが多いでしょう。ただ、本番環境では`console.*`は不要なので実行させないようにしましょう。　
 `yarn add -D babel-plugin-transform-remove-console`でプラグインをインストールし、`babel.config.js`を修正します。

#### babel.config.js
```js
module.exports = function (api) {
  const babelEnv = api.env();
  const plugins = [];
  if (babelEnv !== "development") {
    plugins.push(["transform-remove-console", { exclude: ["error"] }]);
  }
  return {
    presets: [...],
    plugins
  };
};

```

## 画像のファイル形式を変える
　画像のファイル形式でもパフォーマンスに差が出てきます。よく使われるのは`JPEG`と`PNG`ですが、`PNG`形式の画像だと色数を減らしてファイルサイズを落とすことができます。`JPEG`より`PNG`の方がパフォーマンス最適化には優れているといえるでしょう。
 `PNG`より優れたパフォーマンスを発揮するものとして、`WebP`があります。ただ、`WebP`はスマホのosのバージョンによってはサポートされていなかったりします。

## react-native-fast-imageを使う
　react-nativeに組み込まれている`Image`コンポーネントは時に表示が遅く感じることがあります。この問題の解決策としてのおすすめは`react-native-fast-image`を使うことです。組み込みの`Image`コンポーネントとほとんど同じように使うことができ、画像のちらつきや低パフォーマンスの改善が可能になります。
https://www.npmjs.com/package/react-native-fast-image

#### Imageコンポーネント
```jsx
import Image from 'react-native'

const YourImage = () => (
    <Image
        source={{
            uri: '...'
        }}
    />
)
```

#### react-native-fast-image
```jsx
import FastImage from 'react-native-fast-image'

const YourImage = () => (
    <Image
        source={{
            uri: '...'
        }}
    />
)
```

## useNativeDriverを設定
 react-nativeのアニメーションは何も設定しなければ、アニメーションのJSスレッドで実行されます。もし、JSスレッドがスタックしていた場合アニメーションフレームはスキップされます。これを解決するのがuseNativeDriverです。
参考↓
https://reactnative.dev/blog/2017/02/14/using-native-driver-for-animated


```jsx
Animated.timing(this.state.animatedValue, {
  toValue: 1,
  duration: 500,
  useNativeDriver: true, 
}).start();
```

## hermesを使用
 hermes(エルメス)はReact Nativeを拘束に実行するために作られたJSエンジンです。
React NativeのbareworkFlowを使っている場合とexpoを使用している場合で設定方法が変わります。

#### androidの設定
android/app/build.gradle

```gradle
  project.ext.react = [
      entryFile: "index.js",
-     enableHermes: false  // clean and rebuild if changing
+     enableHermes: true  // clean and rebuild if changing
  ]
```

```
$ cd android && ./gradlew clean
```

#### iosの設定
ios/Podfile

```Podfline
   use_react_native!(
     :path => config[:reactNativePath],
     # to enable hermes on iOS, change `false` to `true` and then install pods
-    :hermes_enabled => false
+    :hermes_enabled => true
   )
```
```
cd ios && pod install
```

#### expoの設定
app.json

```json
{
  "expo": {
    "android": {
      "jsEngine": "hermes"
    }
  }
}
```

expoでhermesを使う注意点として、2021年8月24日現在ではandroidのみかつ、EAS(expo application service) buildのみでしかビルドできません。
EAS buildは有料で月$29かかります。
https://expo.dev/pricing
ただ、ビルドさえしてしまうとOTAアップデートもいつも通りできます。

## 最後に
随時更新して情報を追加していきます。