Skip to content

7: Todoの完了状態の更新

前回はTodoの追加機能を作成しました。
今回はTodoの完了状態を更新する機能を作っていきましょう。

  1. 状態の更新

    • 配列の要素の更新
    • オブジェクトのプロパティの更新
  2. 条件付きレンダリング

    • Todoの完了状態に応じたスタイルの切り替え

src/app/todos/page.js を以下の内容に更新します。

'use client';
import style from './page.module.css';
import { useState } from 'react';
export default function Todos() {
const [todos, setTodos] = useState([
{ id: 1, title: '買い物に行く', completed: false },
{ id: 2, title: 'メールを確認する', completed: false },
{ id: 3, title: '資料を作成する', completed: false },
{ id: 4, title: '友達に電話する', completed: false },
{ id: 5, title: '部屋の掃除', completed: false },
]);
// 入力値の状態管理
const [newTodo, setNewTodo] = useState('');
// Todo追加処理
const handleSubmit = (e) => {
e.preventDefault();
if (newTodo.trim() === '') return;
const newId = todos.length > 0 ? Math.max(...todos.map(t => t.id)) + 1 : 1;
setTodos([...todos, { id: newId, title: newTodo, completed: false }]);
setNewTodo('');
};
// 1. Todoの完了状態を更新する処理
const handleToggleComplete = (todoId) => {
setTodos(todos.map(todo =>
todo.id === todoId
? { ...todo, completed: !todo.completed }
: todo
));
};
return (
<section className={style.container}>
<h1>Todoリスト</h1>
{/* Todo追加フォーム */}
<form onSubmit={handleSubmit} className={style.form}>
<input
type="text"
value={newTodo}
onChange={(e) => setNewTodo(e.target.value)}
placeholder="新しいTodoを入力"
className={style.input}
/>
<button type="submit" className={style.button}>追加</button>
</form>
{/* Todo一覧 */}
<div className={style.checkbox}>
{todos.map(todo => (
<div key={todo.id}>
{/* 2. Todoの完了状態に応じたスタイルの切り替え*/}
<label className={todo.completed ? style.completed : ''}>
<input
type="checkbox"
onChange={() =>
// 3. チェックボックスがクリックされたときの処理の登録
handleToggleComplete(todo.id)}
/>
{todo.title}
</label>
</div>
))}
</div>
</section>
);
}
  1. Todoの完了状態を更新する処理

    const handleToggleComplete = (todoId) => {
    setTodos(todos.map(todo =>
    todo.id === todoId
    ? { ...todo, completed: !todo.completed }
    : todo
    ));
    };
    • todoId: 更新対象のTodoのIDを受け取ります
    • todos.map(): 配列の各要素に対して処理を行います
    • todo.id === todoId: 更新対象のTodoを見つけます
    • { ...todo, completed: !todo.completed }: Todoの完了状態を反転させます
    • setTodos(): 更新されたTodo一覧を保存します
  2. Todoの完了状態に応じたスタイルの切り替え

    <label className={todo.completed ? style.completed : ''}>
    • 三項演算子を使用して、Todoの完了状態に応じてクラス名を動的に切り替えます
    • todo.completedtrue の場合は style.completed クラスを適用
    • false の場合は空文字列(デフォルトスタイル)を適用
  3. チェックボックスがクリックされたときの処理の登録

    <input
    type="checkbox"
    onChange={() => handleToggleComplete(todo.id)}
    />
    • onChange イベントハンドラを使用して、チェックボックスの状態変更を検知
    • クリック時に handleToggleComplete 関数を呼び出し、該当するTodoのIDを渡す
    • これにより、チェックボックスの状態に応じてTodoの完了状態が更新される

src/app/todos/page.module.css に以下のスタイルを追加します。

/* 省略 */
.button:hover {
background-color: #0051a2;
}
.completed {
text-decoration: line-through;
color: #888;
}

正しく動作しているか確認しましょう。

  • チェックボックスをクリックするとTodoの完了状態が切り替わる
  • 完了したTodoの見た目が変わる

クリックしても見た目が変わらない

  • イベントハンドラが設定されているか確認する
  • イベントハンドラに書かれている内容に間違いがないか確認する

以下の質問に答えて、学習内容を確認しましょう!

  1. 配列の各要素に処理を適用するときに使う関数は?

    • A: forEach()
    • B: map()
    • C: filter()
    • D: reduce()
答えを見る

答え: B: map()

  • map() は配列の各要素に対して処理を行い、新しい配列を作成します
  • このステップでは特定のTodoの完了状態を更新するために使いました
  1. オブジェクトのプロパティを展開して新しいオブジェクトを作るときに使う演算子は?

    • A: +
    • B: ...
    • C: &&
    • D: ||
答えを見る

答え: B: ...

  • スプレッド演算子(...)は、オブジェクトのプロパティを展開して新しいオブジェクトを作成します
  • このステップでは、Todoオブジェクトのプロパティを更新するために使いました

このステップでは以下について学びました。

  • 状態の更新

    • 配列要素の更新
    • オブジェクトのプロパティの更新
    • スプレッド演算子
  • イベントハンドリング

    • チェックボックスの状態変更イベント
  • 条件付きレンダリング

    • Todoの完了状態に応じたスタイルの切り替え