ノベルティメディア
mediaTodoアプリを作りながら解説するReact Hooks

.jpg&w=1920&q=75)
こんにちは!アシスタントコーダーの山田です。
ノベルティに入社して約2ヶ月が経ちました!
今回は簡単なTodoアプリを作ってみたので、その解説をしていきます。
(Reactに重きを置いているので、HTMLとCSSの説明は省略します)
今回のコラムでわかること
- useStateフックを使用したステートの管理方法
- 配列へのオブジェクトの追加・削除・更新方法
作成したTodoアプリ
今回実装した機能は以下の通りです。
- タスクの追加
- タスク完了状態の更新
- 完了したタスクの削除

環境構築
任意のディレクトリで以下のコマンドを実行し、Reactのプロジェクトを新規に作成します。
‘my-app’の部分は、作成するアプリケーションの名前に置き換えてください。
npx create-react-app my-app
プロジェクトが作成されたら、以下のコマンドで開発サーバーを起動します。
npm start
今回作成するディレクトリの構造は以下のようになります。
src/
├── components/
│ └── TodoList/
│ └── index.jsx
└── App.js
App.jsの編集
srcディレクトリ内のApp.jsを編集し、起点となるコンポーネントを定義します。
TodoListコンポーネントは後ほど作成するので、インポートしておきます。
import TodoList from './components/TodoList'
const App = () => {
return (
<div>
<TodoList />
</div>
)
}
export default App
また、先ほど作成したApp.jsと同じ階層にcomponents/TodoList/index.jsxを作成し、このindex.jsxファイルにTodoListコンポーネントを作成していきます。
useStateでリスト全体の状態を管理する
useStateはReact Hooksの一つで、ユーザーの入力情報などをコンポーネントに保持させることができます。まずはコンポーネントにuseStateをインポートして、TodoList全体の状態管理をするための関数を準備します。
import { useState } from 'react';
const TodoList = () => {
const [todos, setTodos] = useState([
{
id: 1,
task: 'タスク1',
isCompleted: false
},
{
id: 2,
task: 'タスク2',
isCompleted: false
}
])
return (
<div>
<h1>Todoリスト</h1>
</div>
)
}
export default TodoList
useStateフックを使うと、2つの要素が入った配列が返されます。1つ目の要素は現在の値、2つ目の要素は現在の値を更新する関数です。
- 現在の値(todos):現在の値で、初回レンダリング時は初期値を持つ。
- 値を更新する関数(setTodos):ステートを更新すると、コンポーネントが再レンダリングされ、最新の値が反映される。
const [todos, setTodos] = useState([
{
id: 1,
task: 'タスク1',
isCompleted: false
},
{
id: 2,
task: 'タスク2',
isCompleted: false
}
])
今回はステートの引数に
- id(タスクを識別するためのid)
- task(タスクの内容)
- isCompleted(タスクが完了しているかどうかを表す真偽値)
という3つのプロパティを設定しています。各プロパティの値が初期値として設定されます。
Todoリストを表示する
todos配列に格納された先ほどのオブジェクトを、mapメソッドで展開して表示します。mapメソッドは配列の各要素に対して関数を実行し、その結果を新しい配列として返すメソッドです。
以下では、配列の各アイテムを引数として受け取り、JSX要素を返しています。
<li>にはどの要素が変更、追加もしくは削除されたのかを Reactに識別させるためにkey属性を指定します。
<h1>Todoリスト</h1>
<ul>
{todos.map((todo) => (
<li key={todo.id}>
<label>
<input type='checkbox' />
<span>{todo.task}</span>
</label>
</li>
))}
</ul>
このように表示されます。

タスク追加機能
新しいタスクを追加し、表示させていきます。
まずは追加したタスクを一時的に保持する新たなステートを用意します。そして、入力フィールドで発生する変更を検知してこのステートを更新するために、onChangeイベントハンドラを設定します。
const [task, setTask] = useState('');//追加したタスクを一時的に保持するステート
<label htmlFor='task'>やること:</label>
<input
type='text'
id='task'
name='task'
value={task}
onChange={(e) => {
setTask(e.target.value)
}}
/>
<button type='submit'>
追加
</button>
現在のままでは追加ボタンを押しても何も変わりません。追加ボタンを押したときの処理を実装し、それぞれの要素をformで囲って送信処理を追加します。
onSubmit関数のnewIdでは、todos配列の中からidを抽出し、Math.maxメソッドで引数として与えられた数値の中から最大の値を返します。
setTodos()では、スプレッド構文(…prevTodos)が使用されており、これにより現在のTodoリストのすべてのタスクが新しい配列にコピーされ、その配列の最後に新しいオブジェクトが追加されます。
const onSubmit = (e) => {
e.preventDefault()
const newId = todos.length > 0 ? Math.max(...todos.map((todo) => todo.id)) + 1 : 1
const newTodo = { id: newId, task, isCompleted: false }
setTodos((prevTodos) => [...prevTodos, newTodo])
setTask('')
}
<form onSubmit={onSubmit}>
<label htmlFor='task'>やること:</label>
<input
type='text'
id='task'
name='task'
value={task}
onChange={(e) => {
setTask(e.target.value)
}}
/>
<button type='submit'>
追加
</button>
</form>
テキストフィールドに入力して追加ボタンを押すと、新しいタスクが追加されます。

タスク完了状態の更新
todosステート変数のisCompletedでは、各タスクの完了状態を表しています。初期値は’false’であるため、最初は未完了の状態として設定されています。
タスクの完了状態を更新するために、handleToggleComplete関数を使用します。
この関数では、todos配列を先ほども使用したmapメソッドで展開し、配列の各要素のタスクに対して処理を行います。
todo.id(配列内の各要素の値)とid(関数に渡される値)を比較し、条件が真(つまり、todo.idとidが等しい)場合に、isCompletedの値を反転させています。
const handleToggleComplete = (id) => {
setTodos((prevTodos) =>
prevTodos.map((todo) => (todo.id === id ? { ...todo, isCompleted: !todo.isCompleted } : todo))
)
}
この関数をチェックボックスのonChangeイベントにセットします。
checked属性にステートを入れることで、チェックボックスの選択状態とtodo.isCompletedステートが常に同期されるようになります。
完了したことをわかりやすくするために、条件を出し分けてCSSのクラスを適用し、text-decoration: line-throughで打ち消し線を適用しています。
{todos.map((todo) => (
<li key={todo.id}>
<label>
<input
type='checkbox'
checked={todo.isCompleted}
onChange={() => handleToggleComplete(todo.id)}
/>
<span className={todo.isCompleted ? styles.completed : ''}>{todo.task}</span>
</label>
</li>
))}

完了したタスクを削除する
最後に、完了したタスクを削除するボタンを実装します。
filterメソッドで現在の配列を展開し、isCompletedがfalse(チェックされていない)タスクのみを新しい配列に含めることで、完了したタスクを除外しています。
const handleDeleteCompletedTasks = () => {
setTodos((prevTodos) => prevTodos.filter((todo) => !todo.isCompleted))
}
この関数を削除を実行するボタンのonClickイベントハンドラとして設定し、クリックすると完了したタスクを削除できるようになります。
<button type='button' onClick={handleDeleteCompletedTasks}>
完了タスクを削除
</button>
まとめ
今回は簡単なTodoアプリをReactで作成して、useStateや配列メソッドの解説を行いました。
ノベルティでは、Reactを含むモダンなフロントエンド技術を駆使して、クライアントのニーズに合わせた構築技術を提供しています。
興味のある方はぜひお問い合わせを!
↓ この記事をご覧の方へおすすめの記事はこちら ↓
【2024年版】スプレッドシートからメール送信!? GASを使った自動返信メールの作り方!
GASでお手軽DX!チャットツールとカレンダーを連携して業務改善を!
Web担当者必見!企業がアクセシビリティに取り組むことのメリットとは?
\ノベルティではアクセシビリティに関するホワイトペーパーも配布しています/
おすすめ記事/ PICKUP
記事カテゴリー/ CATEGORY
企業の課題はノベルティひとつで完結
ホームページ制作などのWeb制作をはじめ、
システム開発やマーケティング支援などワンストップで対応
まずはお気軽にお問い合わせください
お電話またはメールでお気軽にお問い合わせください。
各種サービスの資料をご用意しています