こんにちは。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で見た目を整える前)。
目次
- 目次
- 本編
- リストを分ける
- 未完→完の機能追加
- 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
こんな感じです。大丈夫ですね。
未完→完の機能追加
では次に、未完リストのタスクを完リストに入れられるようにしましょう。
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()
完了ボタンを押すと上の完リストにタスクが移動できます。
これでひとまず基本的な機能は完成ですね。
上手くいきましたか?上手くいかなかった方はコードをもう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
それではお疲れさまでした。
明日の担当はでっていうさんとあさりくんです。お楽しみに!