Reactの習得にあたって、こちらのUdemyの教材で学習をした内容についてまとめました。
Reactを理解するためにはまずはJavaScriptの習得が必要ということで、JavaScriptのみでTODOリストを作成しています。
Udemyと全く同じではなく、CSSのデザイン部分は少し省いています。
目標物
それではいざコーディングへ!
「追加」ボタンクリックでアラートを表示させる
やりたいこと
追加ボタンを押した時に、ボタンが機能しているか確認するために、まずは試しにalert表示させる。
やること
「追加」ボタンにidを付与
<button id="add-button">追加</button>
付与したidに対してクリックイベントを追加する。
const onClickAdd = () => {
alert();
};
document
.getElementById("add-button")
.addEventListener("click", () => onClickAdd());
これらについて詳しく
const onClickAdd = () => {
alert();
};
これにより、追加ボタンを押したときに関数を実行する。
.addEventListener("click", () => onClickAdd());
これにより、clickイベントで関数onClickAddが実行される。
「追加」ボタンを押した時にフォームに入力された値を変数に渡す
まずはHTMLのinputタグにidを付与する。
<input id="add-text" placeholder="ToDoを入力" />
次にJavaScript側を編集
変数inputTextを定義し、ここにinputで取得した値を入れる。
取得したいのはvalueなので、.valueとする。
const inputText = document.getElementById("add-text").value
これにより、add-textというidが持っているvalueが、inputTextに格納される。
値が渡されたので、「追加」ボタンクリック後にフォームの入力を空欄にする処理をする。
document.getElementById("add-text").value = "";
ここまでのまとめ
const onClickAdd = () => {
const inputText = document.getElementById("add-text").value;
document.getElementById("add-text").value = "";
alert(inputText);
};
document
.getElementById("add-button")
.addEventListener("click", () => onClickAdd());
inputTextの値を”未完了のTODO”に登録していく
DOMの生成は、createElementという関数を使っていく。
const div = document.createElement("div");
console.log(div);
> <div></div>
この関数は、JavaScript上でHTMLのDOMを生成することができる。
divというタグを生成し、divという変数で定義する。
これにより、「追加」ボタンクリックでdivタグを取得できる。
HTMLで、divにはlist-rowというclass名を付与しているため、JavaScriptでも付与する。
const div = document.createElement("div");
div.className = "list-row";
console.log(div);
> <div class="list-row"></div>
JavaScriptの方で、document.createElementを使って、HTMLのDOMを生成して、 HTML に差し込んでいく。
const li = document.createElement("li");
li.innerText = inputText;
liタグの中身に要素を格納したい時は、innerTextを使う。
liタグを生成して、その中にinputTextの値を格納することによって、liタグ内に入力された値が入った状態で出力される。
階層構造を作る
以下のようなタグの階層構造を作る。
<ul id="incomplete-list">
<div class="list-row">
<li>ToDoです</li>
<button>完了</button>
<button>削除</button>
</div>
</ul>
階層を作るにはappendChildを使う。
ここまでをまとめると
const onClickAdd = () => {
const inputText = document.getElementById("add-text").value;
document.getElementById("add-text").value = "";
const div = document.createElement("div");
div.className = "list-row";
const li = document.createElement("li");
li.innerText = inputText;
div.appendChild(li);
console.log(div);
};
consoleの出力結果がこちら
<div class="list-row">
<li>テスト</li>
</div>
index.htmlと同じ階層になっていることがわかる。
最後に、divタグの一個上の階層のulタグにincomplete-listというid名を付け、divを取得し、要素を切り替える。
document.getElementById("incomplete-list").appendChild(div);
ここまでの画面
TODOリストにボタンを追加する
// 完了buttonを生成
const completeButton = document.createElement("button");
completeButton.innerText = "完了";
// 削除buttonを生成
const deleteButton = document.createElement("button");
deleteButton.innerText = "削除";
// HTMLの階層を生成
div.appendChild(li);
div.appendChild(completeButton);
div.appendChild(deleteButton);
completeButtonという変数を定義して、buttonタグを生成し、その中に「完了」「削除」を入れる。
clickイベントを追加して、完了と、削除ボタンをクリックしたときに、alertが表示されるようにして、定義した関数が機能しているかの確認をする。
// 完了buttonを生成
const completeButton = document.createElement("button");
completeButton.innerText = "完了";
completeButton.addEventListener("click", () => {
alert("完了");
});
// 削除buttonを生成
const deleteButton = document.createElement("button");
deleteButton.innerText = "削除";
deleteButton.addEventListener("click", () => {
alert("削除");
});
「削除」ボタンクリックでリストが削除されるようにする
parentNodeを使い、親の要素を取得する。
子要素から指定のものを消す場合はremoveChildを使う。
const deleteButton = document.createElement("button");
deleteButton.innerText = "削除";
deleteButton.addEventListener("click", () => {
const deleteTarget = deleteButton.parentNode;
document.getElementById("incomplete-list").removeChild(deleteTarget);
});
document.getElementByIdについて解説
getElementByIdとは、指定したid値を持つ要素をElementオブジェクトとして返すメソッド
Elementオブジェクト とは何か?
HTMLの要素、つまりタグの認識でよい。
「完了」ボタンも「削除」ボタンと同様にクリックで消す
完了と削除で同じ役割のため、関数化する。
以下の部分を関数化する。
const deleteTarget = deleteButton.parentNode;
document.getElementById("incomplete-list").removeChild(deleteTarget);
関数化により以下のようになる。
const deleteFromIncompleteList = (target) => {
document.getElementById("incomplete-list").removeChild(target);
呼び出し側
deleteFromIncompleteList(deleteButton.parentNode);
「完了」ボタンを押したときに”未完了のTODO”のから”完了したTODO”に移行する
完了ボタンの親要素を取得して変数addTargetと定義する
const addTarget = completeButton.parentNode;
取得した親要素の中の一番最初の子要素のtextを取得する。
const text = addTarget.firstElementChils.innerText;
上記で生成したaddTargetのtextを削除する。
addTarget.textContent = null;
完了したTODOに入れるためにliタグを作成し、その中に上記で定義したtextを入れる。
const li = document.createElement("li");
li.innerText = text;
“完了したTODO”から”未完了のTODO”に戻すための「戻す」ボタンを作成
const backButton = document.createElement("button");
backButton.innerText = "戻す";
これら作成した要素を完了したTODOの子要素に設定
これで、階層構造はできたので、あとは完了したリストに表示する。
document.getElementById("complete-list").appendChild(addTarget);
「戻す」ボタンの機能を作成する
戻すボタンの親タグの要素を完了リストから削除
const deleteTarget = backButton.parentNode;
document.getElementById("complete-list").removeChild(deleteTarget);
テキストを取得する。
document.getElementById("complete-list").appendChild(addTarget);
取得したテキストを基に、未完了のTODOに要素を追加する。
「追加」をしたときとほとんど同じなので関数化して、両方で使えるようにする。
関数定義
const createIncompleteList = (text) => {
この中に共通部分を入れる
}
関数呼び出し側
createIncompleteList(引数);
この引数の中に「追加」と「戻す」ボタンクリック時にわたす引数を定義する。
コードの全貌
<!DOCTYPE html>
<html>
<head>
<title>ToDo(JS)</title>
<meta charset="UTF-8" />
</head>
<body>
<div class="input-area">
<input id="add-text" placeholder="ToDoを入力" />
<button id="add-button">追加</button>
</div>
<div class="incomplete-area">
<p>未完了のToDo</p>
<ul id="incomplete-list"></ul>
</div>
<div class="complete-area">
<p>完了したToDo</p>
<ul id="complete-list"></ul>
</div>
<script src="src/index.js"></script>
</body>
</html>
body {
font-family: sans-serif;
}
.input-area {
background-color: #c1ffff;
}
.incomplete-area {
background-color: #c6ffe2;
}
.complete-area {
background-color: #ffffe0;
}
li {
margin-right: 5px;
}
.list-row {
display: flex;
align-items: center;
}
import "./styles.css";
const onClickAdd = () => {
// フォームの入力値を取得とクリア
const inputText = document.getElementById("add-text").value;
document.getElementById("add-text").value = "";
createIncompleteList(inputText);
};
// 「未完了のTODO」からリストを削除
const deleteFromIncompleteList = (target) => {
document.getElementById("incomplete-list").removeChild(target);
};
const createIncompleteList = (text) => {
// divの生成とclass名付与
const div = document.createElement("div");
div.className = "list-row";
// liの生成とliのtextを取得
const li = document.createElement("li");
li.innerText = text;
// 完了buttonを生成
const completeButton = document.createElement("button");
completeButton.innerText = "完了";
// 「完了」ボタンクリックで完了ボタンの親要素ごと未完了のTODOから削除
completeButton.addEventListener("click", () => {
deleteFromIncompleteList(completeButton.parentNode);
// 完了リストに追加する要素
const addTarget = completeButton.parentNode;
const text = addTarget.firstElementChild.innerText;
addTarget.textContent = null;
const li = document.createElement("li");
li.innerText = text;
const backButton = document.createElement("button");
backButton.innerText = "戻す";
backButton.addEventListener("click", () => {
const deleteTarget = backButton.parentNode;
document.getElementById("complete-list").removeChild(deleteTarget);
const text = backButton.parentNode.firstElementChild.innerText;
createIncompleteList(text);
});
addTarget.appendChild(li);
addTarget.appendChild(backButton);
document.getElementById("complete-list").appendChild(addTarget);
});
// 削除buttonを生成
const deleteButton = document.createElement("button");
deleteButton.innerText = "削除";
deleteButton.addEventListener("click", () => {
deleteFromIncompleteList(deleteButton.parentNode);
});
// HTMLの階層を生成
div.appendChild(li);
div.appendChild(completeButton);
div.appendChild(deleteButton);
document.getElementById("incomplete-list").appendChild(div);
};
document
.getElementById("add-button")
.addEventListener("click", () => onClickAdd());
まとめ
主にやっていることは2つだけ
- idを付与して操作する
- 要素の子や親を取得してそこを書き替える
そのためにいろんなメソッドを使用しているが、やっていることはこの2つだけ。
だけど、こんな簡単なTODO機能でも、結構コードが複雑になる。
これをスッキリさせようというのがReact!
コメント