React + TypeScriptでTodoリストを作りながら学んだ、コンポーネントの仕組みと状態管理のポイント
はじめに
最近、React と TypeScript を使ってTodoリストアプリを作成する機会がありました。単純なアプリケーションのように見えて、実は多くの学びがある開発プロセスでした。この記事では、開発中に気づいた興味深いポイントや、つまずいた部分とその解決策について共有します。
使用した技術スタック
- React
- TypeScript
実装のポイント
状態管理と型定義
type Todo = {
value: string;
// 本来はuuidが好ましい
id: number;
checked: boolean;
};
const [todos, setTodos] = useState<Todo[]>([]);
const [value, setValue] = useState<string>("");
Todoの型を明確に定義することで、型安全性を確保しました。各Todoは文字列の値、一意のID、完了状態を持ちます。
イベントハンドリング
入力値の取得
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setValue(e.target.value);
};
React.ChangeEvent<HTMLInputElement>
型を使用することで、入力イベントの型安全性を確保しています。
フォーム送信
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
if (value === "") return;
const newTodo: Todo = {
value: value,
id: todos.length,
checked: false,
};
setTodos([...todos, newTodo]);
setValue("");
};
e.preventDefault()
でフォームのデフォルト送信動作を防ぎ、空の入力を防止しています。
つまずいたポイントと解決策
1. Todoの編集処理
const handleEdit = (id: number, value: string) => {
const newTodos = todos.map((todo) => {
if (todo.id === id) {
todo.value = value;
}
return todo;
});
setTodos(newTodos);
};
なぜmap
を使うのか?
- 状態の不変性を保つため
- 新しい配列を作成し、特定のTodoのみを更新
- Reactの再レンダリングを効率的に行う
2. チェックボックスの状態管理
const handleChecked = (id: number, checked: boolean) => {
const newTodos = todos.map((todo) => {
if (todo.id === id) {
todo.checked = !checked;
}
return todo;
});
setTodos(newTodos);
};
論理否定演算子!
を使用して、現在の状態を反転させています。
3. Todoの削除
const handleDelete = (id: number) => {
const newTodos = todos.filter((todo) => todo.id !== id);
setTodos(newTodos);
};
filter
メソッドを使用して、特定のIDを持つTodoを除外した新しい配列を作成します。
学んだこと
-
型の重要性
- TypeScriptの型定義により、コードの信頼性が向上
- イベントハンドリングの型安全性
-
状態管理の基本
- 不変性の維持
-
map
、filter
を使用した状態更新 - スプレッド演算子による配列の展開
-
イベントハンドリングの奥深さ
- 異なるイベント型の理解
-
preventDefault()
の重要性
おわりに
このTodoリストの開発を通じて、Reactと TypeScriptの基本的な仕組みをより深く理解できました。まだまだ改善の余地はありますが、着実に学びを深めていきたいと思います。