feature image

2022年3月27日 | ブログ記事

ReactでToDoリストを作る(後編)

こんにちは。21Bのmehm8128です。この記事は新歓ブログリレー18日目の記事です。
普段はSysAd班でフロントエンドを担当してWebアプリを作っています。アルゴリズム班で競プロもしてます。
そろそろ「何回記事書くんだこいつ」と思われてそうですが、中高生のためのプログラミング教室、特設ページ、ブログリレーと様々なところでブログを書く機会を得てしまったので許してください。まだ4月下旬にもう1回ブログリレー記事を投稿予定です。

今回はReactでToDoリストを作る話の後編です。前編、中編を読んでいない方はこのリンクこのリンクから読んでみてください。

前回 → https://trap.jp/post/1518/
Github(今回の最終的なコードを確認できます) → https://github.com/mehm8128/ToDoList/tree/day-3

今回の最終形はこちらです。
chrome-capture-2022-2-4

iroriくんとasariくんにサーバーを作ってもらったので、いい感じにできている人もいればうまくいっていない人もいると思いますが、こんな感じかーくらいで見ていただければいいと思います。

サーバーに合わせて作るものを挙げます。

サーバーとの通信には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つずつ確認し、中身のfinishedtrueのものは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

chrome-capture-2022-2-4

3回(サーバー編含むと7回)に渡って記事を書いてきましたが、一通りの流れをつかむことができましたか?今回作ったものを応用すれば色々なWebアプリが作れるようになると思います。また、細かい部分やさらに発展した話はtraPの「Webエンジニアになろう講習会」で学ぶことが出来ます。
興味を持った方は是非traPに入って作りたいものを作ってください!

それではお疲れ様でした。明日の担当はanemoneくんとtoruthiさんです。お楽しみに!

mehm8128 icon
この記事を書いた人
mehm8128

21B工学院。アルゴリズム班とSysAd班に入ってます。

この記事をシェア

このエントリーをはてなブックマークに追加
共有

関連する記事

2022年4月7日
traPグラフィック班の活動紹介
annin icon annin
2021年8月12日
CPCTFを支えたWebshell
mazrean icon mazrean
2021年5月19日
CPCTF2021を実現させたスコアサーバー
xxpoxx icon xxpoxx
2022年4月5日
アーキテクチャとディレクトリ構造
mazrean icon mazrean
2022年3月29日
課題・レポートの作成、何使う?【新歓ブログリレー2022 21日目】
aya_se icon aya_se
2021年5月16日
CPCTFを支えたインフラ
mazrean icon mazrean
記事一覧 タグ一覧 Google アナリティクスについて