React × TypeScript 入門

# はじめに
30代未経験からエンジニアを目指して勉強中のYNと申します。
JavaScriptでReactが書ける人向けの、React × TypeScript入門記事です。

# 新しいReactプロジェクトつくる

```
npx create-recact-app <your-pjt-name> --typescript
```
# コードを書き始める前に
### SnippetからReactコンポーネントのテンプレートを作る
まずはSnippetを作ると楽です。
VScodeであれば、Snippetを使って一瞬でコンポーネントのテンプレートを持って来れます。
![output.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/572098/ae703d3e-d46d-df63-3a5d-cc209486b8c2.gif)

`cmd + shift + p` > `Preference:Configure User Snippets` > `typescriptreact`でスニペットの設定ができます。 `typescriptreact.json`を下記のように変更します。

```typescriptreact.json
{
  "Typescript React Function Component": {
    "prefix": "rh",
    "body": [
      "import React from 'react'",
      "",
      "interface ${TM_FILENAME_BASE}Props {",
      "$1",
      "}",
      "",
      "export const $TM_FILENAME_BASE: React.FC<${TM_FILENAME_BASE}Props> = ({$2}) => {",
      "\t\treturn ($3);",
      "}"
    ],
    "description": "Typescript React Function Component"
  }
}
```

### オートサジェストを有効にする
TypeScriptを使うメリットの一つに、型指定によるオートサジェストにあります。 試しにpropsの場所で`Ctrl`+`Space`を押すと、指定可能なpropsの一覧が表示されます。
![output.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/572098/eb6bc5a1-fc9c-faae-2e6d-ef0267341e49.gif)
VScodeであれば、デフォルトで`Ctrl`+`Space`で有効になっているはずです。
![スクリーンショット 2020-11-14 11.43.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/572098/6d208acb-0c2b-16cb-1b60-52f19553aff2.png)
もし作動しなければ、（Macの場合）`システム環境設定` > `キーボード` > `ショートカット` で `Ctrl`+`Space`の既存ショートカットを無効化しましょう。

# Reactコンポーネントの基本
## Function Component
interfaceで型を定義し、`React.FC`にgenericsとして渡します。

```TextField.tsx
import React from "react";

interface Props {
  text: string;
  ok?: boolean;
  i?: number;
}

export const TextField: React.FC<Props> = ({text ="hello", i=1, ok=true }) => {
  return (
   ...
  );
};
```
## onClick
マウスホバーすれば、定義すべき型がわかります。

```OnClick.tsx
import React from 'react';

interface OnclickProps {
  onClick?: (event: React.MouseEvent<HTMLDivElement, MouseEvent>) => void; 
  // divタグのonClickにカーソルを合わせると、この型を指定すればいいことがわかる
  text?: string;
}

const Onclick: React.FC<OnclickProps> = ({ onClick, text }) => {
  return <div onClick={onClick}>{text}</div>;
};

export const Click: React.FC<OnclickProps> = () => {
  const logText = (e: React.MouseEvent<HTMLDivElement, MouseEvent>) =>
    console.log(e.target);
  return <Onclick onClick={logText} text={'hello!!'} />;
};
```


## Hooks
###useState
Hooksもgenericsで型を定義します。

```Counter.tsx
import React, { useState } from 'react';

interface CounterProps {
  initialCount: number;
}

export const Counter: React.FC<CounterProps> = ({ initialCount }) => {
  const [count, setCount] = useState<number>(initialCount); // countの型をgenericsで指定
  return (
    <>
      <button onClick={() => setCount(count + 1)}>+</button>
      <div>{count}</div>
    </>
  );
};
```
###useReducer
ActionやStateもtypeやinterfaceを使って型を定義します。

```Reducer.tsx
import React, { useReducer } from "react";

type Actions =
  | { type: "add"; text: string }
  | {
      type: "remove";
      idx: number;
    };

interface Todo {
  text: string;
  complete: boolean;
}

type State = Todo[];

const TodoReducer = (state: State, action: Actions) => {
  switch (action.type) {
    case "add":
      return [...state, { text: action.text, complete: false }];
    case "remove":
      return state.filter((_, i) => action.idx !== i);
    default:
      return state;
  }
};

export const ReducerExample: React.FC = () => {
  const [todos, dispatch] = useReducer(TodoReducer, []);

  return (
    <div>
      {JSON.stringify(todos)}
      <button
        onClick={() => {
          dispatch({ type: "add", text: "..." });
        }}
      >
        +
      </button>
    </div>
  );
};

```

# 参考
[Ben Awadさんの動画](https://youtu.be/Z5iWr6Srsj8)
[Snippet](https://gist.github.com/benawad/1e9dd01994f78489306fbfd6f7b01cd3#file-snippets-typescriptreact-json)
[Gif動画を記事に貼るやりかた](https://qiita.com/takasp/items/65d1d0d90073bcfc4873)