Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Vue.jsのreactive周りの仕組みをコードを読んで理解してみる
Search
Kaido Iwamoto
March 15, 2024
Programming
1
350
Vue.jsのreactive周りの仕組みをコードを読んで理解してみる
Kaido Iwamoto
March 15, 2024
Tweet
Share
More Decks by Kaido Iwamoto
See All by Kaido Iwamoto
Kotlin ことはじめ
odiak
1
290
Other Decks in Programming
See All in Programming
[AtCoder Conference 2025] LLMを使った業務AHCの上⼿な解き⽅
terryu16
6
1k
ゆくKotlin くるRust
exoego
1
180
AI Agent Tool のためのバックエンドアーキテクチャを考える #encraft
izumin5210
6
1.5k
Findy AI+の開発、運用におけるMCP活用事例
starfish719
0
2k
Spinner 軸ズレ現象を調べたらレンダリング深淵に飲まれた #レバテックMeetup
bengo4com
1
210
大規模Cloud Native環境におけるFalcoの運用
owlinux1000
0
230
HTTPプロトコル正しく理解していますか? 〜かわいい猫と共に学ぼう。ฅ^•ω•^ฅ ニャ〜
hekuchan
2
590
PC-6001でPSG曲を鳴らすまでを全部NetBSD上の Makefile に押し込んでみた / osc2025hiroshima
tsutsui
0
200
Claude Codeの「Compacting Conversation」を体感50%減! CLAUDE.md + 8 Skills で挑むコンテキスト管理術
kmurahama
1
700
AI Agent Dojo #4: watsonx Orchestrate ADK体験
oniak3ibm
PRO
0
120
LLM Çağında Backend Olmak: 10 Milyon Prompt'u Milisaniyede Sorgulamak
selcukusta
0
140
Pythonではじめるオープンデータ分析〜書籍の紹介と書籍で紹介しきれなかった事例の紹介〜
welliving
3
730
Featured
See All Featured
16th Malabo Montpellier Forum Presentation
akademiya2063
PRO
0
35
Building an army of robots
kneath
306
46k
WCS-LA-2024
lcolladotor
0
400
Jamie Indigo - Trashchat’s Guide to Black Boxes: Technical SEO Tactics for LLMs
techseoconnect
PRO
0
34
Ten Tips & Tricks for a 🌱 transition
stuffmc
0
42
Principles of Awesome APIs and How to Build Them.
keavy
127
17k
Docker and Python
trallard
47
3.7k
Tips & Tricks on How to Get Your First Job In Tech
honzajavorek
0
400
How STYLIGHT went responsive
nonsquared
100
6k
VelocityConf: Rendering Performance Case Studies
addyosmani
333
24k
Bootstrapping a Software Product
garrettdimon
PRO
307
120k
RailsConf & Balkan Ruby 2019: The Past, Present, and Future of Rails at GitHub
eileencodes
141
34k
Transcript
Vue.jsのreactive周りの仕組みをコードを読んで理解して みる
自己紹介 岩本海童 フロントエンドエンジニア Android、サーバーサイドは経験はあるが、最近は趣味で触る程度 React, TypeScriptが得意 去年からVue.jsを初めて仕事で使い始めた
宣伝:趣味で作っているサービスなど Kakeru (https://about.kakeru.app) ブラウザで動く共同編集もできる手書きメモのアプリ 炭水化物量計算くん (https://carbs-calc.pages.dev) 食材とその量を入力して炭水化物量を計算する
本題: Vue.jsのreactiveってどういう仕組みなの? Reactに慣れていると、なんかとても便利で不思議な仕組み 使っていておおよそ仕組みはイメージできるけど、ちゃんとコード読んで確かめたい
かなり雑で、一部のケースを読み飛ばしたりしています。指摘や質問など大歓迎です。
どこから始める? リポジトリ: vuejs/core とりあえず ref() と reactive() 初心者「ほぼ同じでしょ?」 あとは、それらの変更を検知する側である watch()
computed() はたぶん仕組みが同じなので今回はパス
定義場所を探す ref() : packages/reactivity/src/ref.ts reactive() : packages/reactivity/src/ref.ts watch() : packages/runtime-core/src/apiWatch.ts
ref編
ref 関数 createRefを呼んでいるだけ(shallow: false) createRef 関数 new RefImpl()してるだけ
RefImpl クラス (1) valueプロパティのgetter/setterがある _value に toReactive() した値 オブジェクトなら reactive()
でラップ、それ以外はそのまま _rawValue に toRaw() した値 値がreactiveならアンラップしたもの
RefImpl クラス (2) getter trackRefValue を呼ぶ _value を返す setter toRawした新しい値を
_rawValue と比較する 変化していれば、 _value と _rawValue に代入し、 triggerRefValue を呼ぶ
事前知識: ReactiveEffectについて watchやcomputedなどの内部で使われる、reactiveな値が変化した時に実行される処理 のかたまりのようなものです(雑な理解) 参照されたreactiveな値が変化したかどうかのフラグを持つ
runメソッドが呼ばれると、引数で渡された関数(fn)を実行する その際に、関数の内部で参照されたreactiveな値をトラッキングするための準備や その後の後片付けなどを行う 現在実行中のReactiveEffectがモジュールの変数に入っていて、trackEffect関数か ら参照できる triggerやschedulerという引数で与えられた関数が間接的にrunメソッドを呼ぶことにな る
trackRefValue 関数 Refオブジェクトに dep?: Map<ReactiveEffect, number> というプロパティがある キーはRefを参照しているReactiveEffectで、値は何回目の実行か( _trackId )
一方、ReactiveEffectはdepsというプロパティにdepの配列を持っている depがundefinedなら初期化する trackEffect を呼んで現在実行中のReactiveEffectに値が参照されたことを知らせる
trackEffect 関数 (reactive関数の方でも呼ばれる共通のやつ) depsに現在実行中のReactiveEffectとその _trackId をセットする( _trackId につい ては省略) 場合によっては、前の実行のcleanup処理などを行うが、詳細は省略(お茶をにごす)
triggerRefValue 関数 triggerEffect を呼んで、参照しているReactiveEffectに値の変更を通知する triggerEffect 関数 (reactive関数の方でも呼ばれる共通のやつ) RefオブジェクトのdepにのキーになっているReactiveEffectたちの処理を呼び起こす
ref 編 終わり valueが参照されたら参照を記録し、valueが変更されたら変更を通知するという割と素 朴な仕組み (deps周りの処理は少し複雑だけど)
reactive 編(1) 長くなりそうなので手短に refがvalueプロパティを持つオブジェクト(RefImpl)を返したのに対して、こちらはProxy を返します Proxyはプロパティのget/set、関数呼び出しなどをフックできる 与えられたオブジェクトをラップして、元のオブジェクトそっくりに振る舞いなが ら参照や変更を監視する Refと同様にdepプロパティを持っている
reactive 編(2) プロパティのgetが呼ばれた場合... trackEffect を呼び出してReactiveEffectに参照を通知する(depを更新する) オブジェクト本体のプロパティの値を toReactive して返す プロパティのsetが呼ばれた場合 triggerEffectを呼び出してReactiveEffectを呼び起こす
オブジェクト本体のプロパティの値を更新する
(終わり)(短い)
watch 編 doWatch 関数が本体
doWatch 関数(1) 第1引数はいくつかのパターンがあるが、どのパターンも関数でラップされて getter と なる oldValue変数で最後に実行したgetterの戻り値を持っておく job 関数 effectがdirtyなら、effectを実行する(getterの戻り値が返ってくる)
前回から値が変化していれば、コールバックを実行する scheduler 関数 job を次のマイクロタスクで実行する
doWatch 関数(2) effect = ReactiveEffect(getter, NOOP, scheduler) でReactiveEffectを初期化 する unwatch
関数 effectのstopを呼んで無効化する immediateオプションがtrueの場合はeffectを実行して結果をoldValueに入れておく 実行するとscheduler→job→コールバックの流れで呼ばれる unwatchを返す
まとめ
ReactiveEffectというクラスで、関数内で参照されたreactive系のオブジェクトをトラッ キングし、変更された際に通知を受けるとことができる ref関数やreactive関数が返すオブジェクトは、ReactiveEffectからアクセスされると参照 が記録され、変更されるとReactiveEffectに通知される watch関数はReactiveEffectを使って、与えられたref/reactiveオブジェクトや関数の返 す値が変更されたことを検知してコールバックを実行することができる
ありがとうございました。 質問などあればどうぞ!