【勉強用】React×Typescriptの勉強のために簡単なTodoリスト作ってみた

## はじめに
React勉強中の大学4年生です。

インターンを経て大学3年生からフリーランスとして活動しており、Typescriptの学習の必要性を感じたため<b>React×Typescript</b>の学習をスタートしました。

今回は自分の学習のアウトプットも兼ねて、ReactとTypeScriptを使用して簡単なTodoリストを作ってみることにしました。

## アプリケーションの概要
<ul>
<li>使用する技術はReactとTypescript</li>
<li>タスクの追加ができる</li>
<li>タスクの削除ができる</li>
<li>ステートの管理ができる</li>
</ul>

## プロジェクトの立ち上げ
Node.jsをインストールし、以下のコマンドを打つとTypescriptを使用したReactプロジェクトを使用することができます。
```
npx create-react-app {プロジェクト名} --template typescript
```
今回はTodoという名前のプロジェクトを立ち上げるので以下のように記入します。
```
npx create-react-app Todo --template typescript
```
作成したプロジェクトのディレクトリに移動して起動します。
```
cd Todo
npm start
```
このコマンドを実行すると、ブラウザが自動的に開き、http://localhost:3000 でReactアプリケーションが表示されます。Reactのデフォルトのページが表示されれば、プロジェクトの立ち上げは成功です。

## Todoコンポーネントを作成する
Todo.tsxというファイルを新たに作成し、Todoコンポーネントの作成します。

```typescript:Todo.tsx
import React from 'react';

function Todo() {
  return (
    <div className="Todo">
	　<h2>Todoリスト</h2>
	　<input></input>
	　<button>追加する</button>
    </div>
  );
}

export default Todo;
```
<h3>結果</h3>
このTodoリストはまだ何も機能を持っていませんが、Todoリストの基本的なレイアウトができています。
ここから機能を追加していきます。

![Screenshot 2024-07-13 at 20.53.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3837880/70e35fa9-45a9-71e8-7094-361df1405c26.png)

<h2>タスク追加機能の実装</h2>
タスク追加機能の流れを文章化してみます。
<ol>
<li><b>inputにタスクが書き込まれた時</li>
入力フィールドにタスクの内容を書き込む。ユーザーが入力するたびに入力フィールドの内容はリアルタイムで更新されるようにする

<li><b>追加ボタンを押した時</li>
追加するボタンを押すと現在の入力フィールドがタスクとして配列に格納されるようにする
<li><b>新しいタスクオブジェクトが完成</li>
新しいタスクがオブジェクトとして作成される。
<br>このオブジェクトには以下の情報が含まれます：
<ul>
<li>タスクの内容（テキスト）</li>
<li>タスクを識別するための一意のID</li>
</ul>
<li><b>タスクリストが更新される</li>
新しいタスクオブジェクトが既存のタスクリストに追加される。
Reactのステートが更新されることで、画面上のタスクリストが再レンダリングされ、新しいタスクがリストに表示される。
</ol>

これらを順に実装していくと以下のようなコードになる

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

function Todo() {
	type Todo = {
		inputValue: string;
		key:number;
	        };

//inputの状態変化を表す定数
const [inputValue, setInputValue] = useState<string>('');
//タスクの配列
const [todos, setTodos] = useState<Todo[]>([]);

	const handleChange=(e: React.ChangeEvent<HTMLInputElement>)=>{
		setInputValue(e.target.value)
	}

	const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
		e.preventDefault();
		const newTodo: Todo = { inputValue: inputValue, key: Date.now() };
		setTodos([...todos, newTodo]);
		setInputValue('');
	        };

  return (
    <div className="Todo">
	<h2>Todoリスト</h2>
	<form onSubmit={handleSubmit}>
	<input
	type="text"
	value={inputValue}
	onChange={handleChange}></input>
	<button>追加する</button>
	</form>
	<ul>
        {todos.map((todo, index) => (
          <li key={index}>{todo.inputValue}</li>
        ))}
      </ul>
    </div>
  );
}

export default Todo;
```

<h2>タスク削除機能の実装</h2>
タスク削除機能の実装について文章化してみます。
<ol>
<li><b>削除ボタンのクリックイベントを作成</li>
削除ボタンを押すと定義した一意のIDをもとに特定のタスクを消去し、新しい配列を作る
<li><b>タスクリストの更新</li>
クリックイベントハンドラ内で、削除対象のタスクを除外した新しい配列を作成する。`filter`メソッドを使って、削除対象のタスク以外のタスクを抽出する。
<li><b>ステートの更新</li>
新しいタスクリストで状態を更新します。これにより、Reactが再レンダリングされ、削除されたタスクが画面から消えるようにする。
</ol>
これらを実装していくと次のようなコードになる。

```typescript:Todo.tsx
import React, { useState } from 'react';


function Todo() {
	type Todo = {
		inputValue: string;
		key:number;
	        };

//inputの状態変化を表す定数
const [inputValue, setInputValue] = useState<string>('');
//タスクの配列
const [todos, setTodos] = useState<Todo[]>([]);

	const handleChange=(e: React.ChangeEvent<HTMLInputElement>)=>{
		setInputValue(e.target.value)
	}

	const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
		e.preventDefault();
		const newTodo: Todo = { inputValue: inputValue, key: Date.now() };
		setTodos([...todos, newTodo]);
		setInputValue('');
	        };
	
	const handleDelete=(key:number)=>{
                    const newTodos=todos.filter((todo)=>todo.key!==key);
		setTodos(newTodos);
	}

  return (
    <div className="Todo">
	<h2>Todoリスト</h2>
	<form onSubmit={handleSubmit}>
	<input
	type="text"
	value={inputValue}
	onChange={handleChange}></input>
	<button>追加する</button>
	</form>

	<ul>
        {todos.map((todo, index) => (
          <li key={index}>{todo.inputValue}
	<button onClick={() => handleDelete(todo.key)}>削除</button>
	</li>
	
        ))}
      </ul>
    </div>
  );
}

export default Todo;
```


ここまでの実装でTypescriptとJavascriptの記法の違いについてまとめてみる

<h3>TypescriptとJavascriptの記法の違い</h3>
これまでの実装コードの中でのTypescriptとJavascriptの記法の違いは以下の通りである。

①型アノテーション
②型エイリアス
③関数の引数の型を指定することができる
④オブジェクトの型

一つ一つ確認してみる
<h4>①型アノテーション</h4>
TypeScriptでは、変数や関数の引数、戻り値に型を指定することができます。

```typescript
const [inputValue, setInputValue] = useState<string>('');
const [todos, setTodos] = useState<Todo[]>([]);
```
型を指定することのメリットは以下のようなものです。

<ul>
<li>エラーの早期発見</li>
<li>コードの可読性が上がる</li>
<li>自動補完やインテリセンス機能により開発効率が上がる</li>
</ul>

<h4>②型エイリアス</h4>
typeやinterfaceを使ってカスタム型を定義することができる。
型エイリアスは同じ型を再利用したいときに使うと便利。
型の定義が一箇所になるため、保守性が向上する。

```Typescript
type Todo = {
  inputValue: string;
  key: number;
};
```
<h4>③関数の引数の型を指定することができる</h4>
TypeScriptでは、関数の引数に型を指定することで、その関数がどのようなデータを受け取るかを明確にすることができます。

```Typescript
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
  setInputValue(e.target.value);
};
```
<h2>ポイント
<h3>e.preventDefault();の表記</h3>

```Typescript 
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
    e.preventDefault(); // デフォルトのフォーム送信を防ぐ
    const newTodo: Todo = { inputValue: inputValue, key: Date.now() };
    setTodos([...todos, newTodo]);
    setInputValue('');
  };

  ```
formタグにつけたhandleSubmitの中にある「e.preventDefault();」は表記することによって、ボタンが押されるたびにページがリロードされるという表記を直すことができます。