こんにちは。21Bのmehm8128です。この記事は新歓ブログリレー18日目の記事です。
普段はSysAd班でフロントエンドを担当してWebアプリを作っています。アルゴリズム班で競プロもしてます。
そろそろ「何回記事書くんだこいつ」と思われてそうですが、中高生のためのプログラミング教室、特設ページ、ブログリレーと様々なところでブログを書く機会を得てしまったので許してください。まだ4月下旬にもう1回ブログリレー記事を投稿予定です。
今回はReactでToDoリストを作る話の後編です。前編、中編を読んでいない方はこのリンクやこのリンクから読んでみてください。
前回 → https://trap.jp/post/1518/
Github(今回の最終的なコードを確認できます) → https://github.com/mehm8128/ToDoList/tree/day-3
今回の最終形はこちらです。
iroriくんとasariくんにサーバーを作ってもらったので、いい感じにできている人もいればうまくいっていない人もいると思いますが、こんな感じかーくらいで見ていただければいいと思います。
サーバーに合わせて作るものを挙げます。
- GET /tasks 完リストと未完リストの取得
- POST /tasks 未完リストへの追加
- PUT /tasks/:id 未完リストから完リストへの移動
- DELETE /tasks/:id 未完リストから削除
サーバーとの通信にはaxiosというライブラリを使います。
例えば未完リストへの追加は今までhandlePush()
でリストに連結、ということをしてましたが、POST /tasksすればサーバーのデータベースに保存されるのでそのままGET /tasksでデータベースにあるタスク一覧を取ってこようと思います。
axiosを使うには、CodeSandBoxを使っている方は左下の"Add Dependency"に"axios"と入力してクリックすればよいです。そうでない方はコマンドラインでnpm install axios
でaxiosをインスールできます。
それでは準備ができたところで最初にGET /tasksの処理を書きます。
src/components/ToDoList.js
import axios from "axios"
import { useState, useEffect } from "react"
import "./ToDoList.css"
function handleGetTodos() {
axios.get("http://localhost:8000/api/tasks").then((res) => {
let tmpCompletedTodos = []
let tmpTodos = []
for (let i = 0; i < res.data.length; i++) {
if (res.data[i].finished) {
tmpCompletedTodos = tmpCompletedTodos.concat([
{
id: res.data[i].id,
name: res.data[i].name,
},
])
} else {
tmpTodos = tmpTodos.concat([
{
id: res.data[i].id,
name: res.data[i].name,
},
])
}
}
setCompletedTodos(tmpCompletedTodos)
setTodos(tmpTodos)
})
}
useEffect(() => {
handleGetTodos()
}, [])
return(...
一番上のimport文を少し書き換えたあと、return(...の上にこんな感じに追加してください。
useEffect(関数,配列)
では配列の中身の変数に変化があったときに関数を実行してくれます。配列を空にすると、ページを読み込んだときにだけ関数を実行してくれます。配列を書き忘れたり、配列に入れるものによっては関数が無限ループしてしまうおそれがあるので注意してください。
handleGetTodos()
ではGETリクエストを送っています。成功したらthen()
内の関数が処理されます。返ってくるデータはres
に入り、for文でres.data
配列の中身を1つずつ確認し、中身のfinished
がtrue
のものはcompletedTodos
に、false
のものはtodos
に入れるような処理を書いています。そして後でPUTしたりDELETEしたりするtodoがどれなのかをサーバーに伝える必要があるので今回は返ってきたidも保存しています。また、tmp~
みたいな配列はuseStateの仕様上、一時的に配列に保存してから最後に一気に状態変更を行っています。
CodeSandBoxでなくてVSCodeなどでやっている方はuseEffectの第二引数のところで配列が空ですよみたいな警告をESLintに出されてるかもしれません。その場合は
useEffect(() => {
handleGetTodos()
}, []) // eslint-disable-line react-hooks/exhaustive-dep
のようにしてコメントアウトしてここの行のエラーは無視してくださいみたいな指示を出せば消えてくれます(消さなくても今回は問題ありません)。ESLintの設定を変更すればこれを書かなくても出ないようになります。
また、返ってくる1つのtodoは
{id:タスクのID,name:タスク名前}
という形なのでreturn()内を少し書き換えます。
liタグ内でタスクの名前を表示している部分の{completedTodo}
を{completedTodo.name}
に、{todo}
を{todo.name}
に変えてください。
そしてkeyを完タスクはkey={completedTodo.id}
、未完タスクはkey={todo.id}
と修正しておきます。
次にPOST /tasksの処理を書きます。
src/components/ToDoList.js
function handlePush() {
if (todo !== "") {
axios.post("http://localhost:8000/api/tasks", {
name: todo,
}).then(() => {
handleGetTodos()
})
setTodo("")
}
}
既に書いてあるhandlePush()をこれに書き換えて下さい。
POSTリクエストを送っています。POSTリクエストのときにはURLの後にカンマ区切りでサーバーに送るデータを入れる必要があります。そしてそれが成功したら先ほどのhandleGetTodos()
を実行することでリストの中身を更新します。
次にPUT /tasks:idの処理を書きます。
src/components/ToDoList.js
function handleComplete(index) {
axios.put(`http://localhost:8000/api/tasks/` + todos[index].id).then(() => {
handleGetTodos()
})
}
既に書いてあるhandleComplete()をこれに書き換えて下さい。
POSTとほぼ同じようにしてPUTリクエストを送っています。POSTのようにURLの後ろにカンマ区切りでデータを入れることもできますが、今回は未完を完にするだけの処理を決まっているので入れていません。そして成功したらhandleGetTodos()
でリストの中身を更新します。
最後にDELETE /tasks:idの処理を書きます。
中編まではタスクを消すボタンを作っていなかったのですが、未完タスクを完にするのと似たような感じで作れると思うので続きを読む前に自分で考えてみてください。
src/components/ToDoList.js
function handleDelete(index) {
axios.delete(`http://localhost:8000/api/tasks/` + completedTodos[index].id).then(() => {
handleGetTodos()
})
}
<ul className="ul">
{completedTodos.map((completedTodo, index) => (
<li key={index} className="li">
{completedTodo.name}
<button onClick={() => handleDelete(index)} className="button">
タスクを消す
</button>
</li>
))}
</ul>
function handleComplete(index){...}
の下にfunction handleDelete(){...}
を追加します。PUTとほぼ同じです。そしてタスクを消すボタンもこれで作れました。
これで完成です。動いてますか?今回は結構難しいので動かなかったらもう1回コードを確認してみたり、分からなければこの記事のコメント欄に書いて下されば答えます。また、サーバーとの通信なのでサーバーを作るときにどこかミスをしている場合がありますのでそちらも確認してみてください。
今回の全体のコードへのリンクを再掲しておきます。
https://github.com/mehm8128/ToDoList/tree/day-3
3回(サーバー編含むと7回)に渡って記事を書いてきましたが、一通りの流れをつかむことができましたか?今回作ったものを応用すれば色々なWebアプリが作れるようになると思います。また、細かい部分やさらに発展した話はtraPの「Webエンジニアになろう講習会」で学ぶことが出来ます。
興味を持った方は是非traPに入って作りたいものを作ってください!
それではお疲れ様でした。明日の担当はanemoneくんとtoruthiさんです。お楽しみに!