feature image

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

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

こんにちは。21Bのmehm8128です。この記事は新歓ブログリレー11日目の記事です。
普段はSysAd班でフロントエンドを担当してWebアプリを作っています。アルゴリズム班で競プロもしてます。
今回はReactでToDoリストを作る話の中編です。前編を読んでいない方は↓のリンクから読んでみてください。

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

中編の最終形はこちらです(CSSで見た目を整える前)。
------5

目次

  1. 目次
  2. 本編
    1. リストを分ける
    2. 未完→完の機能追加
    3. CSSをつける(おまけ)

本編

それでは続きをやっていきます。
今回作る機能はこちらです。

残りの3つを作っていきましょう。

リストを分ける

まず、今はリストが1つだけですが完と未完の2つのリストに分けなければなりません。
なので、リストをuseStateでもう1つ作成し、ulタグを増やします。

src/components/ToDoList.js

import { useState } from "react"

function ToDoList() {
	const [completedTodos, setCompletedTodos] = useState([])
	const [todos, setTodos] = useState([])
	const [todo, setTodo] = useState("")

	function handlePush() {
		if (todo !== "") {
			setTodos(todos.concat([todo]))
			setTodo("")
		}
	}
	return (
		<div>
			<h1>ToDoリスト</h1>
			<input value={todo} onChange={(e) => setTodo(e.target.value)} />
			<button onClick={handlePush}>登録</button>
			<h2>タスク一覧</h2>
			<h3></h3>
			<ul>
				{completedTodos.map((completedTodo, index) => (
					<li key={index}>{completedTodo}</li>
				))}
			</ul>
			<h3>未完</h3>
			<ul>
				{todos.map((todo, index) => (
					<li key={index}>{todo}</li>
				))}
			</ul>
		</div>
	)
}

export default ToDoList

こんな感じです。大丈夫ですね。
------1-2

未完→完の機能追加

では次に、未完リストのタスクを完リストに入れられるようにしましょう。

src/components/ToDoList.js

import { useState } from "react"

function ToDoList() {
	const [completedTodos, setCompletedTodos] = useState([])
	const [todos, setTodos] = useState([])
	const [todo, setTodo] = useState("")

	function handlePush() {
		if (todo !== "") {
			setTodos(todos.concat([todo]))
			setTodo("")
		}
	}
	function handleComplete(index) {
		setCompletedTodos(completedTodos.concat(todos[index]))
		setTodos(todos.slice(0, index).concat(todos.slice(index + 1)))
	}
	return (
		<div>
			<h1>ToDoリスト</h1>
			<input value={todo} onChange={(e) => setTodo(e.target.value)} />
			<button onClick={handlePush}>登録</button>
			<h2>タスク一覧</h2>
			<h3></h3>
			<ul>
				{completedTodos.map((completedTodo, index) => (
					<li key={index}>{completedTodo}</li>
				))}
			</ul>
			<h3>未完</h3>
			<ul>
				{todos.map((todo, index) => (
					<li key={index}>
						{todo}
						<button onClick={() => handleComplete(index)}>完了する</button>
					</li>
				))}
			</ul>
		</div>
	)
}

export default ToDoList

未完リストのliタグ内に完了ボタンと、return()の上に完了用の関数を増やしました。
では見ていきましょう。

<button onClick={() => handleComplete(index)}>完了する</button>

ボタンがクリックされたら、タスクのindexを引数にしてhandleComplete関数が実行されます。
そしてhandlecomplete関数がこちらです。

function handleComplete(index) {
		setCompletedTodos(completedTodos.concat(todos[index]))
		setTodos(todos.slice(0, index).concat(todos.slice(index + 1)))
	}

indexを引数に取って、1行目ではcompletedTodos(完リスト)にtodos(未完リスト)のindex番目のタスクを追加しています。2行目ではtodos(未完リスト)からindex番目の要素を取り除いたものを新しいtodosに設定しています。
配列.slice()は(第一引数の数字)番目から(第二引数-1)番目の要素だけで配列を生成するものです。Array.prototype.slice()

------3

完了ボタンを押すと上の完リストにタスクが移動できます。
これでひとまず基本的な機能は完成ですね。

上手くいきましたか?上手くいかなかった方はコードをもう1度確認してみて下さい。

CSSをつける(おまけ)

最後におまけとしてCSSをつけて見た目を整えていきます。

まず、componentsディレクトリに新しくToDoList.cssというファイルを作ります。
そしてsrc/components/ToDoList.jsでCSSをつけたいところ(見た目を整えたいところ)にclassNameをつけていきます。普通のHTMLではclass=""でクラス名を指定しますが、ReactではClassName=""でクラス名を指定するところに注意してください。

src/components/ToDoList.js

import { useState } from "react"
import "./ToDoList.css"
return (
		<div className="todoList">
			<h1 className="title">ToDoリスト</h1>
			<input value={todo} onChange={(e) => setTodo(e.target.value)} />
			<button onClick={handlePush} className="button">
				登録
			</button>
			<h2>タスク一覧</h2>
			<h3></h3>
			<ul className="ul">
				{completedTodos.map((completedTodo, index) => (
					<li key={index} className="li">
						{completedTodo}
					</li>
				))}
			</ul>
			<h3>未完</h3>
			<ul className="ul">
				{todos.map((todo, index) => (
					<li key={index} className="li">
						{todo}
						<button onClick={() => handleComplete(index)} className="button">
							完了する
						</button>
					</li>
				))}
			</ul>
		</div>
	)

2行目で先ほど作ったCSSファイルをimportし、return()内のいくつかのタグにclassNameをつけました。これでToDoList.cssファイルでclassNameを指定してCSSを書けば反映されます。
ちなみに僕はCSS書くの苦手なので(コードを書く技術的な意味でもデザインのセンス的な意味でも)おかしいところがあるかもしれませんが自分で色々調べて工夫してみてください。

src/components/ToDoList.css

.todoList {
	display: block;
	text-align: center;
	margin-right: auto;
	margin-left: auto;
	width: 50%;
}
.title {
	color: green;
}
.ul {
	padding: 0;
	width: 50%;
	margin-right: auto;
	margin-left: auto;
	list-style: none;
}
.li {
	padding-bottom: 8px;
	margin-bottom: 8px;
}
.button {
	background-color: aqua;
	margin-left: 4px;
    border-radius: 8px;
	border: solid 1px black;
	cursor: pointer;
}

これで見た目がいい感じになります。それぞれのプロパティについての詳細は調べてみてください。
※タスクは数ヶ月前のものです。
---

ひとまずこれで完成です。2日間お疲れさまでした。
しかし、この記事は中編です。まだ後編があります。これだけだとページをリロードしたときにデータが消えてしまいますよね。そこで、データを保存したり他にも色々といい感じのことをできるようにするためにサーバーを作り、サーバーと通信をできるようにします。
次回からは僕と同じく21Bのiroriくんとasariくんがサーバーを作る記事を書いてくれるのでサーバーが完成したらそれと通信するためのコードをまた僕が解説する、という形になります。ついていけなくなったら大体どんな感じでWebアプリが作られるのか、おおまかな流れだけでも理解していただきたいです。分からないことがあったらこのブログのコメント欄に書いてください!

今回の全体のコードへのリンクを再掲しておきます。
https://github.com/mehm8128/ToDoList/tree/day-2

それではお疲れさまでした。
明日の担当はでっていうさんとあさりくんです。お楽しみに!

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年9月26日
競プロしかシラン人間が web アプリ QK Judge を作った話
tqk icon tqk
2022年4月5日
アーキテクチャとディレクトリ構造
mazrean icon mazrean
2022年3月29日
課題・レポートの作成、何使う?【新歓ブログリレー2022 21日目】
aya_se icon aya_se
記事一覧 タグ一覧 Google アナリティクスについて