【第9回】Reactが何を代わりにやっているのかが分かる|DOM操作(嫁子が教えるTS講座)
今回のゴール
- HTMLの中身をJavaScriptで書き換えられる
- ボタンを押したときの処理(イベント)が書ける
- 第4部で学ぶReactが何を代わりにやるのかが分かる
前回(非同期処理)までは、実行しても文字が出るだけでした。今回から画面が動きます。全体の流れは講座の目次へ。
嫁子: 今日でようやく「作ってる感」が出るよ。ここまでずっと
console.logだったからね。ただし正直に言っておくと、今日のやり方は、第4部でReactに置き換わるの。じゃあ無駄かというと逆で、Reactが何をラクにしてくれているのかは、この面倒くささを知らないと分からないんだよ。
「昔はこうやってたのか」を1回だけ体験する回、くらいに思っててね。
① DOMとは何か
ブラウザはHTMLを読み込むと、それを操作できる形に変換してメモリ上に持ちます。これがDOM(ドム)です。
第1回で「ブラウザがHTMLを解釈して画面を作る」という話をしましたが、その解釈した結果が置いてある場所だと考えてください。
JavaScriptから触るのは、HTMLファイルそのものではなくDOMです。だからファイルを書き換えなくても、画面だけを変えられます。
② 用意するファイル
HTMLとJavaScriptを1つのフォルダに置きます。
<!doctype html>
<html lang="ja">
<body>
<h1 id="title">こんにちは</h1>
<button id="btn">押す</button>
<script src="app.js"></script>
</body>
</html>
id は目印です。JavaScriptから探すときに使います。
<script src="app.js"> は「このJavaScriptを読み込んで実行して」という指定です。</body> の直前に置きます。先に書くと、まだ存在しないHTMLを探しに行ってエラーになります。
③ 要素を取ってきて、書き換える
const title = document.getElementById("title");
title.textContent = "書き換えました";
getElementById は「この id の要素を探して持ってくる」という命令です。取ってきた要素の textContent に代入すると、画面の文字がその場で変わります。
よく使うものだけ挙げておきます。
| 書き方 | すること |
|---|---|
textContent |
文字を書き換える |
value |
入力欄の中身を取る・入れる |
classList.add("done") |
CSSのクラスを足す(見た目を変える) |
style.color = "red" |
直接スタイルを変える |
嫁子:
innerHTMLっていうのも見かけると思うけど、あれはHTMLごと差し込める分、危ないの。外部から来た文字をそのまま入れると、悪意のあるコードを実行させられることがあるんだよ。だから文字を入れたいだけなら
textContentを使ってね。AIがinnerHTMLを使っていたら、そこは一度立ち止まるといいよ。
④ ボタンを押したときに動かす
「クリックされたら実行する」を登録します。
const btn = document.getElementById("btn");
btn.addEventListener("click", () => {
title.textContent = "押されました";
});
addEventListener は「この出来事が起きたら、この関数を実行して」という登録です。第7回でやったアロー関数が、ここで出てきます。
登録した時点では実行されず、クリックされたときに初めて動きます。第7回の最後に書いた「addTax と addTax() は別物」という話が、まさにここで効いてきます。
btn.addEventListener("click", doSomething()); // ✕ 読み込んだ瞬間に実行される
btn.addEventListener("click", doSomething); // ○ クリック時に実行される
嫁子: 括弧をつけると、その場で実行した結果を登録することになるの。だから「ページを開いた瞬間に動いてしまう」ってなるんだね。
括弧なしなら、関数そのものを預けることになる。「あとでこれをやって」と渡すか、「今やった結果」を渡すかの違いだよ。
⑤ 入力を受け取る
入力欄の中身は value で取れます。
<input id="name" type="text">
<button id="add">追加</button>
<p id="result"></p>
const input = document.getElementById("name");
const result = document.getElementById("result");
document.getElementById("add").addEventListener("click", () => {
result.textContent = input.value + " を追加しました";
});
ここで第4回の話を思い出してください。input.value は必ず文字列です。数値を入力しても文字列で届くので、計算に使うなら Number(input.value) で変換します。
嫁子: 第4回で「フォームの数字は文字列で届く」って言ったの、覚えてる? ここがその現場だよ。
個数を足したつもりが
"11"になるやつね。この事故を型で防ぐのが、次の第3部なの。だんだんつながってきたでしょ。
⑥ この書き方の限界
ここまでで画面は動かせます。ただ、規模が大きくなると急につらくなります。
- 表示する項目が10個あれば、10個ぶん
getElementByIdと書き換えが要る - データが変わるたびに、どこを書き換えるか自分で全部指定する必要がある
- 書き換え漏れがあっても、エラーは出ない(画面が古いまま残る)
Reactのようなフレームワークは、この「どこを書き換えるか」を自動でやってくれます。データを変えれば画面が追従する、という形に変わります。
嫁子: だから第4部に入ると、
getElementByIdはほぼ書かなくなるの。でも今日やったことが無駄になるわけじゃないよ。Reactが裏でやっているのは、結局これだからね。中で何が起きているか想像できる人と、魔法だと思ってる人では、詰まったときの強さが全然違うよ。
つまずきポイント
null が出たら、id が合っていません。存在しない id を指定すると null が返り、その先で「null の textContent は読めません」というエラーになります。打ち間違いか、<script> を書く位置が早すぎるかのどちらかです。
確認はブラウザの開発者ツールで。F12キー(Macは Cmd + Option + I)で開き、Consoleタブに console.log の結果とエラーが出ます。エラーの文面はそのままAIに貼れば伝わります。
今回のまとめ
- DOMは、ブラウザがHTMLを解釈して操作できる形にしたもの
getElementByIdで要素を取り、textContentなどで書き換えるinnerHTMLは避け、文字を入れるだけならtextContentaddEventListenerでクリック時の処理を登録する(関数は括弧なしで渡す)- 入力欄の
valueは必ず文字列。計算するならNumber()で変換 - 手動で書き換える方式には限界があり、それを解決するのが第4部のReact
次にやること
次回は第2部の総合演習、買い物メモアプリです。ここまでに出てきたものを全部使って、実際に動くものを1つ作ります。
今回の宿題:上のHTMLとJavaScriptを作って、ボタンを押すと文字が変わるところまで確認してください。自分の書いたコードで画面が動くのは、ここが初めてになります。
嫁子: 動いた瞬間、けっこう嬉しいと思うよ。第1回から数えて9回目だからね。
AIに全部作らせてもいいんだけど、この回だけは自分で打ってみてほしいな。ここまで読んできたものが1つにつながる感覚は、読むだけだと出てこないから。