【React×TypeScript】初心者向けTodoアプリ作成
はじめに
今回は、ReactとTypeScriptで簡易的なTodoアプリを作成したのですが、Props
やState
などの重要な概念の理解が深まったので、共有したいと思います。
Todoアプリ概要
アプリとしては以下の機能がある非常に簡易的なものになっております。
- Todoリスト表示
- Todo追加・登録機能
- Todo削除機能
以下、実際に作成したものの挙動になります。
実装内容
まずは最上位のコンポーネントから見ていきましょう。
Appコンポーネント
最上位のコンポーネントのためTodoコンポーネント
の呼び出しを行っているのみになります。
import "./App.css";
import Todo from "./components/Todo";
const App = () => {
return (
<>
<div className="app">
<h2>Reminder</h2>
<Todo />
</div>
</>
);
};
export default App;
各コンポーネント
続いて、componentsフォルダ
にある各部品について見ていきましょう。
①Todoコンポーネント
import React, { useState } from "react";
import { TodoList } from "../types/TodoList";
import Form from "./Form";
import List from "./List";
/**
* Todoリストの全機能を実装するコンポーネント
*
* @returns
*/
const Todo = () => {
const todosList: TodoList[] = [
{
id: 1,
content: "店予約する",
},
{
id: 2,
content: "卵買う",
},
{
id: 3,
content: "郵便出す",
},
];
const [todos, setTodos] = useState<TodoList[]>(todosList);
/**
* Todoの削除を行う関数
*
* @param id number
* @returns void
*/
const deleteTodo = (id: number) => {
const newTodos: TodoList[] = todos.filter((todo) => todo.id !== id);
setTodos(newTodos);
};
/**
* Todoの登録を行う関数
*
* @param todo {TodoList}
* @returns void
*/
const createTodo = (todo: TodoList) => setTodos([...todos, todo]);
return (
<>
<List todos={todos} deleteTodo={deleteTodo} />
<Form createTodo={createTodo} />
</>
);
};
export default Todo;
ここでTodoリストに関する機能の実装を行なっています。
上から順にポイントを説明していきます。
まず、Todoの操作についてはState
で状態管理したいためuseState
でTodoList型
を扱うようにしています。
次に各機能についてですが、最初に削除機能について説明します。
削除は一意にTodoを特定することが必要になるため、引数にidを取り、引数に渡ってきたidに該当するTodoを除いたものをsetTodos()
に設定したいので、State
で管理しているTodoにfilter()
を使用し、削除されたTodo以外を抽出するようにしています。
次に登録機能については、配列に新しくTodoを追加する処理になるため、このような記述となっています。
ちなみに、TodoList型はtypesフォルダ
で以下のようにファイルで定義しています。
export type TodoList = {
id: number;
content: string;
};
②Listコンポーネント
import React from "react";
import { TodoList } from "../types/TodoList";
type Props = {
todos: TodoList[];
deleteTodo: (id: number) => void;
};
/**
* Todo一覧を構成するコンポーネント
*
* @param todos {TodoList[]}
* @param deleteTodo {(id: number) => void}
* @returns
*/
const List = ({ todos, deleteTodo }: Props) => {
return (
<div>
{todos.map((todo) => (
<div key={todo.id}>
<button onClick={() => deleteTodo(todo.id)}>完了</button>
<span>{todo.content}</span>
</div>
))}
</div>
);
};
export default List;
Listコンポーネントですが、こちらでまずポイントとなるのは、TypeScriptならではのPropsの型定義を行う部分です。
これがないとPropsが渡された時に「暗黙的にanyが含まれている」というエラーが出力されます。
そのため、Propsとして渡された値を確実に定義する必要があります。
また、Listコンポーネントの引数にPropsの値を分割代入して、型付けを行うことも必要です。
JSXに関しては、Todoをリスト表示するため、map()
を使用し、直下の子要素にkey
を設定し、contentプロパティを表示するようにしています。
また、ボタンが押された際にイベントを発火し、Todoを削除する処理を行なうようにしています。
③Formコンポーネント
import React, { FormEvent, useState } from "react";
import { TodoList } from "../types/TodoList";
type Props = {
createTodo: (todo: TodoList) => void;
};
/**
* Todo入力欄を構成するコンポーネント
*
* @param createTodo {(todo: TodoList) => void}
* @returns
*/
const Form = ({ createTodo }: Props) => {
const [enteredTodo, setEnteredTodo] = useState<string>("");
/**
* フォーム送信時にTodoを追加するための関数
*
* @param e onSubmitイベント
* @returns
*/
const addTodo = (e: FormEvent<HTMLFormElement>) => {
e.preventDefault();
// 入力欄が空の場合、処理を抜ける
if (enteredTodo === "") return;
// 追加するTodoオブジェクトの作成
const newTodo: TodoList = {
id: Math.floor(Math.random() * 1e5),
content: enteredTodo,
};
// Todo登録
createTodo(newTodo);
// 入力欄を空にする
setEnteredTodo("");
};
return (
<div>
<form onSubmit={addTodo}>
<input
type="text"
value={enteredTodo}
onChange={(e) => setEnteredTodo(e.target.value)}
/>
<button>追加</button>
</form>
</div>
);
};
export default Form;
こちらの実装では、まず入力欄で入力された値を保持するためのState
が必要になるので、これをuseState
を用いて定義します。
これを定義したら、JSXと紐づける必要があるのでinputタグ
のvalue属性
にuseStateの参照値を値として定義します。
また、入力欄に入力された際の入力値を保持するため、onChangeイベント
も定義してuseStateの更新関数に渡します。
これが実装できたら、実際にTodoを追加する処理を実装します。
そのために、formのイベントであるonSubmitイベント
を設定します。
このイベントですが、デフォルトではformタグ
のaction属性
が発動するようになっており、これが発動すると、指定したURLに画面遷移するようになっています。(何も指定しない場合は、現在の画面に遷移)
つまり、onSubmit
が発火するとページのリロードが起きてしまいます。
そのためe.preventDefault()
でページのデフォルト動作を無効化してあげる必要があります。
あとは、実際にTodoを登録する処理の実装になるのですが、これは以下の手順で簡単に実装できます。
①追加するTodoListオブジェクトを作成する
②Propsとして渡されたcreateTodo()
を実行する
これでTodo追加・登録処理は完了です。
さいごに
Todoアプリ自体に作れるものですが、Reactのみの場合とTypeScriptをテンプレートに使用した場合では、Propsの実装等で難易度が上がるかと思います。
また、基礎的な内容ではありますが、Reactの重要な概念を学ぶには非常に学ぶ点が多いので、初学者の方など参考にしていただけると幸いです。
Discussion