Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Vue のリアクティブシステム / Reactivity In Vue

ryotah
August 27, 2018

Vue のリアクティブシステム / Reactivity In Vue

merpay Tech Talk #1 で発表したスライドです。Vue のリアクティブシステム、その中でも依存関係のある関数の収集と再実行をどのように実現しているのかについて解説しています。Object.defineProperty, Dep Class and Watcher.

ryotah

August 27, 2018
Tweet

Other Decks in Programming

Transcript

  1. ஋ஈͱ਺͔Β߹ܭֹۚΛදࣔ͢ΔΞϓϦέʔγϣϯ <!-- html --> <div id="app"> <div>price: {{ price }}</div>

    <div>quantity: {{ quantity }}</div> <div>total: {{ total }}</div> </div> // js const app = new Vue({ el: '#app', data: { price: 100, quantity: 2 }, computed: { total() { return this.price * this.quantity; } } }); https://stackblitz.com/edit/vue-reactivity
  2. • data • Vue ΠϯελϯεͷͨΊͷσʔλΦϒδΣΫτ • Vue Πϯελϯε͕࡞੒͞ΕΔͱϦΞΫςΟϒ γεςϜʹ௥Ճ͞ΕΔ •

    computed • Vue Πϯελϯεʹ૊Έࠐ·ΕΔࢉग़ϓϩύ ςΟ • ࢉग़ϓϩύςΟ͸ґଘؔ܎ʹ΋ͱ͖ͮΩϟο γϡ͞ΕΔ
  3. let data = { price: 100, quantity: 2 }; let

    total = data.price * data.quantity; console.log(total); // => 200 data.quantity = 3; console.log(total); // => 300 ?
  4. let data = { price: 100, quantity: 2 }; //

    ࠶ܭࢉͰ͖ΔΑ͏ʹؔ਺Λอଘ let target = () => data.total = data.price * data.quantity; target(); console.log(data.total); // => 200 data.quantity = 3; target(); console.log(data.total); // => 300 // https://stackblitz.com/edit/vue-reactivity-step-by-step?file=step-96.js
  5. export let target = null; export class Dep { constructor()

    { this.subscribers= []; } depend() { if (target && !this.subscribers.includes(target)) { this.subscribers.push(target); } } notify() { this.subscribers.forEach(sub => sub()); } }
  6. let data = { price: 100, quantity: 2 }; let

    watcher = () => data.total = data.price * data.quantity; const dep = new Dep(); target = watcher; dep.depend(); target(); target = null; console.log(data.total); // => 200 data.quantity = 3; dep.notify(); console.log(data.total); // => 300 // https://stackblitz.com/edit/vue-reactivity-step-by-step?file=step-97.js
  7. Object.keys(data).forEach(key => { let _value = data[key]; Object.defineProperty(data, key, {

    get() { console.log('get', key, _value); return _value; }, set(value) { console.log('set', key, _value); _value = value; } }); });
  8. Object.keys(data).forEach(key => { let _value = data[key]; const dep =

    new Dep(); Object.defineProperty(data, key, { get() { dep.depend(); return _value; }, set(value) { _value = value; dep.notify(); } }); }); // ... target = watcher; target(); target = null;
  9. ׬੒ console.log(data.total); // => 200 data.quantity = 3; console.log(data.total); //

    => 300 https://stackblitz.com/edit/vue-reactivity-step-by- step?file=step-99.js
  10. export class AppComponent { price: number; quantity: number; constructor() {

    this.price = 100; this.quantity = 2; (window as any).app = this; } get total() { return this.price * this.quantity; } } // ίϯιʔϧ͔Β࣮ߦ window.app.quantity = 10; // => DOM͸ߋ৽͞Εͳ͍ // => ϘλϯΫϦοΫͳͲΛ͢Δͱ൓ө͞ΕΔ https://stackblitz.com/edit/vue-reactivity-case-of- angular
  11. instance/state • https://github.com/vuejs/vue/blob/v2.5.17/src/ core/instance/state.js#L48 export function initState (vm: Component) {

    • https://github.com/vuejs/vue/blob/v2.5.17/src/ core/instance/state.js#L54 initData(vm) • https://github.com/vuejs/vue/blob/v2.5.17/src/ core/instance/state.js#L112 function initData (vm: Component) {
  12. observer/index • https://github.com/vuejs/vue/blob/v2.5.17/src/ core/observer/index.js export function observe (value: any, asRootData:

    ?boolean): Observer | void { • https://github.com/vuejs/vue/blob/v2.5.17/src/ core/observer/index.js#L123 ob = new Observer(value) • https://github.com/vuejs/vue/blob/v2.5.17/src/ core/observer/index.js#L37 export class Observer {