React-nativeで環境だけ整えて満足した記事(react-native + expo + typescript + NativeBase + why-did-you-render-eslint)

# overview
以下の導入方法を示す。
この記事は結構丁寧なメモです。

* react-native
* expo
* typescript
* NativeBase
* why-did-you-render
* eslint

## expo install
```bash
$ npm install -g expo-cli
```

## プロジェクト用意
```bash
$ expo init react-native-sample
✔ Choose a template: › tabs (TypeScript)     several example screens and tabs using react-navigation and TypeScript
✔ Downloaded and extracted project files.

🧶 Using Yarn to install packages. You can pass --npm to use npm instead.

✔ Installed JavaScript dependencies.

✅ Your project is ready!

To run your project, navigate to the directory and run one of the following yarn commands.

- cd react-native-sample
- yarn start # you can open iOS, Android, or web from here, or run them directly with the commands below.
- yarn android
- yarn ios
- yarn web

$ yarn start
yarn run v1.22.10
$ expo start
Starting project at /Users/matsumoto/Documents/MyWork/react-native-sample
Expo DevTools is running at http://localhost:19002
Opening DevTools in the browser... (press shift-d to disable)
Starting Metro Bundler

 exp://192.168.XX.XX:19000
~QR割愛~
 To run the app with live reloading, choose one of:
 › Scan the QR code above with the Expo app (Android) or the Camera app (iOS).
 › Press a for Android emulator, or i for iOS simulator, or w to run on web.
 › Press e to send a link to your phone with email.
```

### [expo](https://play.google.com/store/apps/details?id=host.exp.exponent&hl=ja&gl=US)をインストールしてQRを読み込む
QRを読み込むと以下のような画面が出力される。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/702045/b8d9018d-9482-54e4-17b9-cdbb5701b6d1.png)


## [NativeBase](https://github.com/GeekyAnts/NativeBase)を導入する
UIライブラリNativeBaseを導入する

### install
```bash
$ yarn add native-base

# NativeBase は Font.loadAsync を使ってロードできるカスタムフォントをいくつか使用しているため、インストールが必要
$ expo install expo-font
```

### ファイルの修正
`useCachedResources.ts`ファイルにてフォントの読み込みを行う。

```useCachedResources.ts
import { Ionicons } from '@expo/vector-icons';
import * as Font from 'expo-font';
import * as SplashScreen from 'expo-splash-screen';
import * as React from 'react';

export default function useCachedResources() {
  const [isLoadingComplete, setLoadingComplete] = React.useState(false);

  // Load any resources or data that we need prior to rendering the app
  React.useEffect(() => {
    async function loadResourcesAndDataAsync() {
      try {
        SplashScreen.preventAutoHideAsync();

        // Load fonts
        await Font.loadAsync({
          Roboto: require("native-base/Fonts/Roboto.ttf"),
          Roboto_medium: require("native-base/Fonts/Roboto_medium.ttf"),
          ...Ionicons.font,
          "space-mono": require("../assets/fonts/SpaceMono-Regular.ttf"),
        });
      } catch (e) {
        // We might want to provide this error information to an error reporting service
        console.warn(e);
      } finally {
        setLoadingComplete(true);
        SplashScreen.hideAsync();
      }
    }

    loadResourcesAndDataAsync();
  }, []);

  return isLoadingComplete;
}
```

`EditScreenInfo.ts`を修正してNativeBaseのボタンを表示してみる

```EditScreenInfo.ts
import React from 'react';

import { Container, Text, Button } from "native-base";

export default function EditScreenInfo({ path }: { path: string }) {
  return (
    <Container>
      <Button>
        <Text>start working on your app!</Text>
      </Button>
    </Container>
  );
}
```
### 画面確認
導入できた。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/702045/232cc053-ce76-93ec-2082-46c1103b256e.png)


## [why-did-you-render](https://github.com/welldone-software/why-did-you-render)導入
### install

```bash
$ yarn add @welldone-software/why-did-you-render
```

### setting
`wdyr.ts`をプロジェクトルートに作成

```wdyr.ts
import React from "react";
import whyDidYouRender from "@welldone-software/why-did-you-render";
if (process.env.NODE_ENV === "development") {
  whyDidYouRender(React, {
    trackAllPureComponents: true,
  });
}
```

`App.tsx`を修正

```App.tsx
import './wdyr'

import { StatusBar } from 'expo-status-bar';
import React from 'react';
import { SafeAreaProvider } from 'react-native-safe-area-context';

import useCachedResources from './hooks/useCachedResources';
import useColorScheme from './hooks/useColorScheme';
import Navigation from './navigation';

export default function App() {
  const isLoadingComplete = useCachedResources();
  const colorScheme = useColorScheme();

  if (!isLoadingComplete) {
    return null;
  } else {
    return (
      <SafeAreaProvider>
        <Navigation colorScheme={colorScheme} />
        <StatusBar />
      </SafeAreaProvider>
    );
  }
}
```

### レンダリングされた理由のログを確認
導入はできた。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/702045/0852dd05-8b2f-5532-f1f9-4f59033dcb92.png)


## eslint導入
### install
```bash
$ yarn add eslint
$ yarn add eslint-plugin-react @typescript-eslint/eslint-plugin @typescript-eslint/parser eslint-plugin-react-hooks
```

### setting
#### 初期設定を行う
```
$ ./node_modules/.bin/eslint --init
✔ How would you like to use ESLint? · style
✔ What type of modules does your project use? · esm
✔ Which framework does your project use? · react
✔ Does your project use TypeScript? · No / Yes
✔ Where does your code run? · browser, node
✔ How would you like to define a style for your project? · guide
✔ Which style guide do you want to follow? · airbnb
✔ What format do you want your config file to be in? · JSON
~割愛~
✔ Would you like to install them now with npm? · No / Yes
~割愛~
```

eslintの設定を行う

``` .eslintrc.json
{
    "env": {
        "browser": true,
        "es2021": true,
        "node": true
    },
    "extends": [
        "airbnb",
        "eslint:recommended",
        "plugin:react/recommended",
        "plugin:@typescript-eslint/eslint-recommended",
        "plugin:@typescript-eslint/recommended",
        "plugin:@typescript-eslint/recommended-requiring-type-checking"

    ],
    "settings": {
        "import/resolver": {
            "node": {
                "extensions": [
                    ".js",
                    ".jsx",
                    ".ts",
                    ".tsx",
                    ".json",
                    ".native.js"
                ]
            }
        }
    },
    "parser": "@typescript-eslint/parser",
    "parserOptions": {
        "project": "./tsconfig.json",
        "ecmaFeatures": {
            "jsx": true
        },
        "ecmaVersion": 12,
        "sourceType": "module"
    },
    "plugins": [
        "react",
        "@typescript-eslint"
    ],
    "ignorePatterns": ["node_modules/"],
    "rules": {
        "import/extensions": [
            "error",
            "ignorePackages",
            {
                "js": "never",
                "jsx": "never",
                "ts": "never",
                "tsx": "never"
            }
        ],
        "no-use-before-define": "off",
        "@typescript-eslint/no-use-before-define": [
            "off"
        ],
        "react/jsx-filename-extension": [
            2,
            { 
                "extensions": [".js", ".jsx", ".ts", ".tsx"]
            }
        ],
        "react/jsx-props-no-spreading":"off",
        "@typescript-eslint/explicit-module-boundary-types":"off",
        "react/destructuring-assignment":"off",
        "react/display-name":"off",
        "react/prop-types":"off",
        "react/no-unescaped-entities":"off"
    }
}
```

#### 参考
https://github.com/software-mansion/react-native-screens/issues/62
https://stackoverflow.com/questions/55614983/jsx-not-allowed-in-files-with-extension-tsxeslintreact-jsx-filename-extensio

### eslint --fixを実行する
`package.json`の`scripts`に以下を追加

```package.json
  "scripts": {
    ...
    "lint": "eslint --ext .ts,.tsx ./"
  },
```

 実行する

```bash
$ yarn lint --fix
```
エラーがいっぱい出るので修正する。

## ここまでの内容をGithubで。
* [react-native-sample](https://github.com/NoriyukiMatsumoto/react-native-sample/commit/66d0f69df26602029833607decfc937b950da029)
 * スターが欲しい

## 所感
アプリで作りたいものができたらこれを利用する。
意外とすんなりできた感ある。