React useStateで作るシンプルToDoアプリ

React HookのuseStateを使ってできるだけシンプルなReactのTodoアプリケーションの作成を行います。
Reactを使い始めたばかりの人であればuseStateを利用した配列へのオブジェクトの追加、削除、更新方法がわからない人も多いと思います。Todoアプリはそれらの処理をすべて含んでいるのでReactビギナーの人にとってアプリケーション作成の基礎を学ぶのに一番良い教材です。…XXXのspread operatorsが頻繁に出てくるのでこの記事を通して使いこなせるように慣れていきましょう。

目次
環境の構築
任意のディレクトリでnpx crate-react-appを実行してReactのプロジェクトの開発環境を構築します。
実行が環境したらmy-appディレクトリに移動してnpm startコマンドを実行します。
npm startコマンドが完了したら、ブラウザが自動で起動しReactのトップページが表示されれば環境構築は完了です。
ToDoアプリケーションの作成
作成の準備
Reactインストールディレクトリの下にあるsrcディレクトリの下にあるApp.jsファイルを下記のように変更を行います。TodoのアプリケーションのコードはToDoListファイルの中に記述するためToDoListファイルをimportしています。
TodoList.jsファイルの作成
TodoList.jsファイルはsrcディレクトリの下にcomponentsディレクトリを作成してその下に保存します。
作成開始時のToDoList.jsファイルには下記を記述します。
Todoリストの元になる配列initialStateには、3つのタスクがオブジェクトで保存されています。useStateにinitialStateを指定することでtodosにはTodoリストが保存されます。todosの更新にはsetTodosを利用して行います。
ブラウザで確認すると画面にはToDo Listと表示されます。

ToDoリストの表示
ToDoリストを画面上に表示するためにTodoリストが保存されているtodosをmap関数で展開します。
ブラウザで確認を行うとtodosに保存されている3つのタスクがリスト表示されます。

inputタグの設定とuseStateの追加
新しいタスクを追加するためのinputタグをリストの上に追加します。
ブラウザで確認すると入力枠が表示されます。

入力した情報を保持するための新しい変数taskをuseStateで追加します。
inputタグに入力した値を取得するためにonChangeイベントを設定し、value属性の値に追加したtaskを指定します。onChangeイベントで実行する関数名は、handleNewTaskとします。
onChangeイベントを設定すると文字を入力するたびにイベントが発行されます。
イベント時に実行されるhandleNewTask関数を追加します。inputで入力した値はevent.target.valueで取得することができるので、取得できているかconsole.logを利用して確認します。
文字を入力する度にコンソールログに入力した文字が表示されれば正常に動作しているので、console.logからsetTaskに変更を行います。
上記のようにsetTaskに変更すると文字を入力すると入力欄に入力した文字が表示されます。

Formの設定
入力したタスクをtodoリストに保存するためにFormタグを追加する必要があります。FormタグにはonSubmitイベントを追加します。onSubmitイベントで実行する関数名は、handleSubmitとします。ボタンをonSubmitイベントによりEnterを押すとhandelSubmitが実行されます。
タスク追加機能の追加
input要素に入力した文字列をtodosに追加するためにhandleSubmit関数を追加します。
通常のHTMLのフォームではsubmitを実行するとページのリロードが行われます。event.preventDefault()を設定することで通常の動作を停止させています。
handleSubmit関数の中では、useStateで追加した2つの変数のtaskとtodosさらにSetTodosとSetTaskを利用します。
taskには入力欄で入力した文字列が入っているはずなので文字列に何も値がない場合は処理が終わります。文字列が入っている場合は、setTodosによりtodosリストに新しいタスクを追加します。setTaskでは入力欄に入力した文字はTodoリストに追加されるのでその文字を入力欄から削除しています。
下記の部分が既存のTodoリストに入力欄で入力した値を追加している処理です。spread operatorを利用しています。
ブラウザ上で入力欄に入力した文字がTodoリストに追加されます。追加する際はEnterボタンを押してください。下記では追加により4つのタスクになっています。空白のままEnterを押しても何も起こりません。


setTodosで配列にオブジェクトを追加する前に…todosや{task, isCompleted:false}がどういった形のものなのかコンソールに表示して確認しておきましょう。
下記のような形であることが確認できます。

タスクの削除機能を追加
タスクの追加が行えたので次はタスクの削除機能を追加します。
liタグにspanタグで囲んでXを追加します。
タスクの右にXが表示されます。

このXをクリックするとタスクが削除されるように設定を行なっていきます。spanタグにonClickイベントを追加し、関数をhandleRemoveTaskとします。
handleRemoveTask関数を追加します。handleRemoveTaskでは削除するタスクを識別するためにindexを渡します。
handleRemoveTaskの中では現在のTodoリストをspread operatorを利用して新しい配列newTodosに保存します。spliceメソッドを利用して配列のindex番目の要素を1つ削除しています。削除後はsetTodosで新しいTodoリストで既存のTodoリストを書き換えています。
設定後、Xをクリックするとタスクが削除することができます。3つのタスクが削除になり2つになっています。すべてのタスクを削除することも可能です。

タスクの削除ではfilter関数を利用することもできます。filter関数では削除を行うのではなくindexを持ったtodoを取り除いています。
ここまでの処理でReact HookのuseStateを利用して、タスクを追加、削除するToDoリストが完成しました。完成時の動作は下記の通りです。

タスク更新機能の追加
Xをクリックするとタスク一覧から削除を行っていましたが、削除ではなくタスクの完了か未完了かを表すisCompletedの値を更新します。
handleRemoveTaskをhandleupdateTaskに変更します。
isCompletedがtrueの場合はタスクが完了したのでタスクが完了したことを表すためstyleのtextDecorationLineをline-throughに文字列の上に横棒を設定します。
最後にhandleUpdateTaskメソッドを追加します。handleUpdateTaskの引数で設定したindexとtodos配列のindexが一致したtodoのisCompletedの値を現在設定されている値を逆の値に設定しています。trueであればfalseになり、falseであればtrueになります。
Xをクリックすると横棒が表示され、横棒が表示されている状態でクリックすると横棒が非表示となります。

削除機能と更新機能を同時追加
削除機能と更新機能を別々に実装しましたが新たにチェックボックスを利用して更新機能を削除機能とは別に追加します。チェックボックはinput要素のtypeをcheckboxとしています。onChageイベントで設定しているhandleUpdateTaskは先ほど更新機能の際に作成したものです。

ここまで作成したコード
作成したコード全体は下記となります。
コンポーネント化
作成したコードはすべてTodoList.jsファイルに記述されていましたがTodoList.jsファイルからTodo.js, TodList.js, AddTodo.jsファイルの3つのファイルに分割します。
Todo.jsファイルにはtodosの初期値とTodoList.jsとAddTodo.jsファイルをimportしてpropsでtodosとsetTodosを渡します。
AddTodo.jsファイルではタスクの追加の処理のみ記述します。
TodoList.jsはpropsのtodosを受け取りtodosを展開して表示し、更新、削除の関数を設定しています。
App.jsファイルからはTodoList.jsファイルではTodo.jsファイルをimportします。
1つのTodoList.jsファイルをコンポーネント化して3つのファイルに分割しましたが処理できる内容は変わりません。