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
260
Vue.jsのreactive周りの仕組みをコードを読んで理解してみる
Kaido Iwamoto
March 15, 2024
Tweet
Share
More Decks by Kaido Iwamoto
See All by Kaido Iwamoto
Kotlin ことはじめ
odiak
1
280
Other Decks in Programming
See All in Programming
競技プログラミングへのお誘い@阪大BOOSTセミナー
kotamanegi
0
390
為你自己學 Python
eddie
0
500
EC2からECSへ 念願のコンテナ移行と巨大レガシーPHPアプリケーションの再構築
sumiyae
3
550
Package Traits
ikesyo
1
160
今年のアップデートで振り返るCDKセキュリティのシフトレフト/2024-cdk-security-shift-left
tomoki10
0
330
PHPで作るWebSocketサーバー ~リアクティブなアプリケーションを知るために~ / WebSocket Server in PHP - To know reactive applications
seike460
PRO
2
720
Оптимизируем производительность блока Казначейство
lamodatech
0
880
MCP with Cloudflare Workers
yusukebe
2
270
PHPUnitしか使ってこなかった 一般PHPerがPestに乗り換えた実録
mashirou1234
0
390
ATDDで素早く安定した デリバリを実現しよう!
tonnsama
1
1.2k
PHPとAPI Platformで作る本格的なWeb APIアプリケーション(入門編) / phpcon 2024 Intro to API Platform
ttskch
0
360
Fixstars高速化コンテスト2024準優勝解法
eijirou
0
170
Featured
See All Featured
JavaScript: Past, Present, and Future - NDC Porto 2020
reverentgeek
47
5.1k
Design and Strategy: How to Deal with People Who Don’t "Get" Design
morganepeng
127
18k
No one is an island. Learnings from fostering a developers community.
thoeni
19
3.1k
How GitHub (no longer) Works
holman
312
140k
Designing on Purpose - Digital PM Summit 2013
jponch
116
7k
Practical Tips for Bootstrapping Information Extraction Pipelines
honnibal
PRO
10
850
GraphQLの誤解/rethinking-graphql
sonatard
68
10k
Unsuck your backbone
ammeep
669
57k
Build The Right Thing And Hit Your Dates
maggiecrowley
33
2.5k
Docker and Python
trallard
43
3.2k
What’s in a name? Adding method to the madness
productmarketing
PRO
22
3.2k
Bash Introduction
62gerente
609
210k
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オブジェクトや関数の返 す値が変更されたことを検知してコールバックを実行することができる
ありがとうございました。 質問などあればどうぞ!