search
LoginSignup
16
Help us understand the problem. What are the problem?

More than 1 year has passed since last update.

posted at

updated at

React × TypeScript 入門

はじめに

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

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

npx create-recact-app <your-pjt-name> --typescript

コードを書き始める前に

SnippetからReactコンポーネントのテンプレートを作る

まずはSnippetを作ると楽です。
VScodeであれば、Snippetを使って一瞬でコンポーネントのテンプレートを持って来れます。
output.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
VScodeであれば、デフォルトでCtrl+Spaceで有効になっているはずです。
スクリーンショット 2020-11-14 11.43.04.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さんの動画
Snippet
Gif動画を記事に貼るやりかた

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
16
Help us understand the problem. What are the problem?