公開日
- 12 分で読めます
第3話 「h関数とVNodeの不思議な世界」
どうしてもVue.jsが分からないので森の博士の研究所に押しかけてみたら、人生が激変した子タヌキの話
注
この物語は、フロントエンド技術を楽しく学ぶことを目的に、生成AIを活用して執筆されています。 技術的な情報の正確性には細心の注意を払っていますが、その内容がすべて真実であることを保証するものではありません。 あくまで学習の補助ツールとして、肩の力を抜いてお楽しみください。
登場人物紹介
- フロントエンド博士: 森の奥の研究所に住む、フロントエンドのことなら何でも知っている物知り博士。ポン吉の素朴な疑問にいつも優しく(そして面白おかしく)答えてくれる。
- ポン吉: 好奇心旺盛な子タヌキ。将来の夢はフロントエンドエンジニア。最近Vue.jsを学び始めたが、その奥深さに興味津々。新しい知識をゲットすると、思わず「ポン!」と飛び跳ねる特技あり。
第3話🦝「h関数とVNodeの不思議な世界」
研究所の扉を叩く音がする。博士が扉を開けると、そこには目を輝かせたポン吉が立っていた。
ポン吉: 「博士、こんにちは!今日はh
関数の秘密を教えてくれるんですよね!ポン!」
博士: 「うむ、ポン吉。やる気満々じゃな。さあ、入りなさい。」
ポン吉は席に着くと、早速モニターに向かった。
博士: 「前回、template
はh
関数に変換されるという話をしたな。今日はそのh
関数を実際に使って、色々なものを作ってみよう。」
博士はキーボードを叩き、新しいコードを書き始めた。
import { createApp, h } from 'vue'
const App = {
render() {
return h('div', { class: 'container' }, [
h('h1', { style: 'color: red;' }, 'すごいタイトル'),
h('p', 'これはh関数で作った段落です。'),
h('ul', [
h('li', 'リスト1'),
h('li', 'リスト2'),
])
])
}
}
createApp(App).mount('#app')
ポン吉: 「わあ!なんだか複雑ですね…。h
関数の中に、またh
関数が入ってる…」
博士: 「そうじゃろう。h
関数の三番目の引数には、子要素を配列として渡すことができるんじゃ。こうやって、HTMLの入れ子構造を表現するんじゃよ。」
ポン吉がコードを実行すると、ブラウザには赤い文字のタイトルと、段落、そしてリストが表示された。
ポン吉: 「本当だ!HTMLと同じものが表示されてる!h
関数って、HTMLのタグを組み立てるための関数なんですね!でも、博士…」
ポン吉は首をかしげた。
ポン吉: 「どうして、わざわざこんな書き方をするんですか?普通にHTMLを書く方がずっと簡単なのに…」
博士は満足そうに頷いた。
博士: 「核心に迫る、良い質問じゃな、ポン吉。その答えは、h
関数が一体『何』を返しているかを知ることで見えてくる。」
博士: 「h
関数は、HTMLの文字列を直接作っているわけではないんじゃ。これは、『VNode』、つまり『仮想ノード』と呼ばれる、ただのJavaScriptオブジェクトを作っておるんじゃよ。」
ポン吉: 「VNode…?仮想のノード…?」
博士: 「うむ。『ノード』というのは、HTMLでいう<div>
や<p>
といった一つ一つの要素のことじゃ。それを、まずはJavaScriptの世界で、仮想的なオブジェクトとして表現するんじゃな。」
博士は黒板にh('p', 'こんにちは')
というコードが返すオブジェクトのイメージを描いた。
// h('p', 'こんにちは') が返すVNode(仮想ノード)のイメージ
{
type: 'p',
props: null,
children: 'こんにちは'
}
ポン吉: 「へぇー!ただのオブジェクトなんですね!これなら僕でも分かりそうです!」
博士: 「そうじゃ。そしてVue.jsは、このVNodeという設計図をもとにして、実際のDOM(つまり、ブラウザ上の本当の画面)に変更を加えるんじゃ。」
ポン吉: 「どうして、そんな面倒なことを…?直接、画面を書き換えちゃダメなんですか?」
博士: 「それはな、実際のDOM操作は、とても『コストが高い』、つまり時間がかかる作業だからじゃ。もしデータが変わるたびに毎回、画面全体を書き換えていたら、アプリケーションはとても遅くなってしまう。」
博士: 「そこでVue.jsは、まずJavaScriptの世界でVNodeを比較し、どこが変わったかだけを特定する。そして、その差分だけを実際のDOMに適用するんじゃ。これを『仮想DOM』の仕組みと呼ぶんじゃよ。これにより、最小限の変更で済むため、非常に高速に画面を更新できるんじゃ。」
ポン吉は目を丸くして聞いていた。
ポン吉: 「すごい…!つまり、h
関数でVNodeという設計図を作って、その設計図上で変更点を見つけてから、本当に必要な部分だけを工事する、みたいな感じですか?」
博士: 「おお!ポン吉、完璧な例えじゃ!その通り!template
は便利な道具じゃが、Vue.jsのこの賢い魔法の仕組みを理解するには、まず魔法の『素材』であるVNodeと、それを生み出すh
関数を知ることが大切なんじゃよ。」
ポン吉は、h
関数がただの面倒な書き方ではなく、Vue.jsの速さの秘密を握る、とても重要なものなのだと理解した。
ポン吉: 「博士、ありがとうございます!VNodeのことが分かったら、h
関数を書くのが楽しくなってきました!ポン!」
博士: 「うむ、その調子じゃ。では次回は、createApp
関数が一体何を返しているのか、その戻り値の正体を探ってみようかの。」
ポン吉: 「はい!よろしくお願いします!」
ポン吉は、また一つ賢くなって、誇らしげに研究所を後にした。
🌟 今日のまとめ
h
関数 は入れ子にすることで、複雑なHTML構造も表現できる。h
関数が返しているのは、HTML文字列ではなくVNode
(仮想ノード) というJavaScriptオブジェクト。VNode
は、実際のDOMの「設計図」のようなもの。- Vue.jsは、この
VNode
を使って差分だけを計算し、画面を効率的に更新する(仮想DOM)。だから速い!
次回予告 「createAppが返すもの」
createApp
関数を実行した後に得られるものとは一体…?ポン吉がAppインスタンスの謎に迫ります!
👨🏫 博士からの補足
ポン吉には、分かりやすく「ただのJavaScriptオブジェクト」と説明したVNodeじゃが、実際にはもう少し複雑なんじゃよ。
実際のVueのVNodeは、type
、props
、children
以外にも、key
(要素を一意に特定するID)、ref
(要素を直接参照するための仕組み)、shapeFlag
(要素の種類を効率的に判定するフラグ)、patchFlag
(最適化のためのヒント情報)など、Vue.jsが高速に動作するための様々な情報を持っておるんじゃ。
また、わしが「設計図」と例えたVNodeじゃが、正確には「設計図の断片」と言った方が良いかもしれん。なぜなら、VNodeは木構造(ツリー)になっており、一つのVNodeは親子関係の中で意味を持つからなんじゃ。この木全体を「VNodeツリー」や「仮想DOMツリー」と呼ぶんじゃよ。
そして、ポン吉に「仮想DOM」という魔法を紹介したが、実はこのアイデアを最初に世に広めたのはVue.jsではなく、Reactというライブラリなんじゃよ。
昔々、ウェブページがどんどん複雑になってくると、DOMを直接操作するのがとても大変になってきた。特に、データが頻繁に変わるアプリケーションでは、画面のどこを更新すべきかを管理するのが非常に困難になったんじゃ。
そこで2013年頃、Reactの開発者たちが「一度JavaScriptの世界で仮想的なDOMを作って、新しい状態と古い状態を比較し、差分だけを実際のDOMに適用しよう」という革新的なアイデアを思いついたんじゃ。これが「仮想DOM」の始まりなんじゃな。
Vue.jsは、このReactの素晴らしいアイデアを参考にしながらも、直感的で理解しやすい形で実装したんじゃよ。
フロントエンドの世界では、こうやって技術者たちがお互いの良いアイデアを参考にしながら、それぞれの哲学に基づいて改良を重ね、どんどん進歩していくんじゃ。競争ではなく、協調と発展の美しい例じゃな。
第3話 おわり