本章では、前章で書いたコードのリファクタリングをします。
リファクタリングとは既存のコードを修正して、より良いコードに仕上げることです。
ToDoリストのタスクを追加する処理と、削除する処理は重なったコードがあります。
これを関数化させて共通化することによって、メンテナンス性の高いコードにします。
リファクタリングしてメンテナンスのいいコードを書こう!
目次
サンプルコードをダウンロードしよう
次のリンクから、サンプルコードをダウンロードしてください。
参考 ToDoアプリサンプルコードJavaScript入門サンプルコードをテキストエディタで開いてみよう
「Visual Studio Code」から、先ほどダウンロードしたファイルから「共通処理を関数化させよう」を選択して開いてみましょう。
開くと次のような画面になります。
サンプルコードをChromeで開いてみよう
サンプルコードの「スタート」の「index.html」をChromeで開いてみましょう。
タスクを削除する機能の共通化
まずは、タスクを削除する機能を見てみましょう。
サンプルコードの「スタート」の「index.js」を見てみましょう。
「タスクを削除しよう1」と「タスクを削除しよう2」という記述があります。
// タスクを削除しよう1
const deleteButton = clone.querySelector(".delete")
deleteButton.addEventListener("click", () => {
const target = document.getElementById(t.id)
tbody.removeChild(target)
document.removeEventListener("click", deleteButton)
})
// タスクを削除しよう2
const deleteButton = clone.querySelector(".delete")
deleteButton.addEventListener("click", () => {
const target = document.getElementById(task.id)
tbody.removeChild(target)
document.removeEventListener("click", deleteButton)
})
この2つを見ると、コードの内容はほぼ同じです。
これを1つの関数にして共通処理としてまとめましょう。
タスクを削除する関数を定義しよう
サンプルコードの「スタート」の「index.js」を見てみましょう。
「タスクを削除する関数を定義しよう」という記述あります。
その真下に、次のように書いてください。
const addDeleteListener = (tbody, button, id) => {
button.addEventListener("click", () => {
const target = document.getElementById(id)
tbody.removeChild(target)
document.removeEventListener("click", button)
})
}
「addDeleteListener
」という関数名にしました。
関数の引数に、「tbody
」、「button
」、「id
」を指定しています。
引数の役割は次の通りです。
引数 | 内容 |
tbody | リストのDOM要素 |
button | 削除ボタンのDOM要素 |
id | 削除対象のID |
関数に置き換えよう
次に、最初にあげた二つの箇所をこの関数を使って置き換えてみましょう。
サンプルコードの「スタート」の「index.js」を見てみましょう。
まずは、一つ目の「タスクを削除しよう1」を置き換えます。
// タスクを削除しよう1
const deleteButton = clone.querySelector(".delete")
deleteButton.addEventListener("click", () => {
const target = document.getElementById(t.id)
tbody.removeChild(target)
document.removeEventListener("click", deleteButton)
})
こちらを次のコードに書き換えてください。
// タスクを削除しよう1
const deleteButton = clone.querySelector(".delete")
addDeleteListener(tbody, deleteButton, t.id)
引数として、「tbody
」、「deleteButton
」、「id
」を渡しています。
そして、次は「タスクを削除しよう2」を置き換えます。
// タスクを削除しよう2
const deleteButton = clone.querySelector(".delete")
deleteButton.addEventListener("click", () => {
const target = document.getElementById(task.id)
tbody.removeChild(target)
document.removeEventListener("click", deleteButton)
})
こちらを次のコードに書き換えてください。
// タスクを削除しよう2
const deleteButton = clone.querySelector(".delete")
addDeleteListener(tbody, deleteButton, task.id)
これで、削除処理を関数化することができました。
引数にそれぞれのDOM要素とidを渡すことによって、中身の処理は共通化させることができました。
タスクを追加する機能の共通化
タスクを追加する処理も共通化することができそうです。
サンプルコードの「スタート」の「index.js」を見てみましょう。
同じ処理が2箇所あることに気づくはずです。
この部分も関数化できそうですね。
タスクを追加する関数を定義しよう
サンプルコードの「スタート」の「index.js」を見てみましょう。
「タスクを削除する関数を定義しよう」という記述あります。
その真下に、次のように書いてください。
// タスクを追加する関数を定義しよう
const addTask = (tbody, task) => {
const clone = template.content.cloneNode(true)
const tr = clone.querySelector("tr")
const name = clone.querySelector(".name")
const deleteButton = clone.querySelector(".delete")
tr.setAttribute("id", task.id)
name.textContent = task.name
// タスクを削除する
addDeleteListener(tbody, deleteButton, task.id)
tbody.appendChild(clone)
}
関数に置き換えよう
次に、1箇所目を関数に置換えてみましょう。
こちらを次のコードに書き換えてください。
tasks.forEach((t) => {
addTask(tbody, t)
})
次に、2箇所目を関数に置換えてみましょう。
こちらを次のコードに書き換えてください。
form.addEventListener("submit", (event) => {
event.preventDefault()
const input = document.getElementById('input')
const value = input.value
if (!value) return
const task = { id:tasks.length + 1, name:value }
addTask(tbody, task)
})
これで、タスクを追加する処理を共通化させることができました。
完成形のコードを見てみよう
最後に、完成形のコードを見てみましょう。
const tasks = [
{ id: 1, name: "部屋の後片付け" },
{ id: 2, name: "お買い物" },
]
const template = document.getElementById('taskTemplate')
const tbody = document.getElementById("tasks")
// タスクを削除する関数を定義しよう
const addDeleteListener = (tbody, button, id) => {
button.addEventListener("click", () => {
const target = document.getElementById(id)
tbody.removeChild(target)
document.removeEventListener("click", button)
})
}
// タスクを追加する関数を定義しよう
const addTask = (tbody, task) => {
const clone = template.content.cloneNode(true)
const tr = clone.querySelector("tr")
const name = clone.querySelector(".name")
const deleteButton = clone.querySelector(".delete")
tr.setAttribute("id", task.id)
name.textContent = task.name
// タスクを削除する
addDeleteListener(tbody, deleteButton, task.id)
tbody.appendChild(clone)
}
tasks.forEach((t) => {
addTask(t)
})
const form = document.getElementById('form')
form.addEventListener("submit", (event) => {
event.preventDefault()
const input = document.getElementById('input')
const value = input.value
if (!value) return
const task = { id:tasks.length + 1, name:value }
addTask(task)
})
const deleteAllButton = document.getElementById("deleteAll")
deleteAllButton.addEventListener("click", () => {
const tbody = document.getElementById("tasks")
tbody.innerHTML = ""
})
関数で共通化させることによって、同じコードを何回も書く必要がなくりましたね。
まとめ
本章では、ToDoリストのタスクを追加する処理と、削除する処理をリファクタリングしました。
同じようなコードを共通化させて関数にすることでコードのメンテナンス性を向上させることができました。
ToDoアプリのまとめ
本章で「ToDoアプリ」のチュートリアルは完成です。
実際に動くものを作ってJavaScriptがどのように使われるのかをイメージできたかと思います。
ToDoアプリを通じて、イベントやイベントハンドラの使い方、template要素の使い方、配列データの使い方などを実践的に学ぶことができたと思います。
「JavaScript入門」で学んだこともこのチュートリアルで生かすことができました。
一度書いただけでは理解できなかったところがあると思います。
そのときは、もう一度チュートリアルを最初から見て、実際に手を動かして コードを書いてみてください。
分からない文法があれば、「JavaScript入門の基礎編」を復習してみてください。
何回も確認して復習すると、分からなかったところがスッと理解できたりします。
プログラミング学習は手を動かして、動くものを作って、なぜ動くのかを理解しながら学習するのが一番の近道です。
最初は大変かと思いますが、諦めずに一緒に頑張りましょう!