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

Vue Reactivity: Learning By Accident

Vue Reactivity: Learning By Accident

Lightning talk at VueConf US 2018 in New Orleans.

Vue's reactivity system makes it dead simple to write components in a readable declarative syntax. But how does it actually work? We'll use the annoying gotchas in the system as an excuse to go deeper and really learn how it works under the hood.

Jeff Schenck

March 28, 2018
Tweet

More Decks by Jeff Schenck

Other Decks in Programming

Transcript

  1. Vue Reactivity https://speakerdeck.com/jeffschenck/vue-reactivity-learning-by-accident export default { data () { return

    { price: 10, quantity: 3, } }, computed: { total () { return this.price * this.quantity }, }, } <p>{{ total }}</p> TOTALLY WORKING CODE
  2. Vue Reactivity https://speakerdeck.com/jeffschenck/vue-reactivity-learning-by-accident export default { data () { return

    { quantity: 3, } }, computed: { total () { return this.price * this.quantity }, }, created () { this.price = 10 }, } <p>{{ total }}</p> TOTALLY NOT WORKING CODE https://codepen.io/jeffschenck/pen/yKpzPJ
  3. Vue Reactivity https://speakerdeck.com/jeffschenck/vue-reactivity-learning-by-accident export default { data () { return

    { price: null, quantity: 3, } }, computed: { total () { return this.price * this.quantity }, }, created () { this.price = 10 }, <p>{{ total }}</p> TOTALLY FIXED WORKING CODE
  4. Vue Reactivity https://speakerdeck.com/jeffschenck/vue-reactivity-learning-by-accident export default { data () { return

    { todos: ['eat', 'sleep', 'vue'], } }, methods: { addTodo () { this.todos.push('more vue') }, }, } <button @click="addTodo()"> Add </button> <ul> <li v-for="todo in todos"> {{ todo }} </li> </ul> TOTALLY WORKING CODE
  5. Vue Reactivity https://speakerdeck.com/jeffschenck/vue-reactivity-learning-by-accident export default { data () { return

    { todos: ['eat', 'sleep', 'vue'], } }, methods: { updateTodo () { this.todos[0] = 'coffee' }, }, } <button @click="updateTodo()"> Update </button> <ul> <li v-for="todo in todos"> {{ todo }} </li> </ul> TOTALLY NOT WORKING CODE https://codepen.io/jeffschenck/pen/geoGeJ
  6. Vue Reactivity https://speakerdeck.com/jeffschenck/vue-reactivity-learning-by-accident Object.defineProperty(obj, key, { get: function reactiveGetter ()

    { const value = getter ? getter.call(obj) : val if (Dep.target) { ... } return value }, set: function reactiveSetter (newVal) { const value = getter ? getter.call(obj) : val if (newVal === value ...) return val = newVal childOb = !shallow && observe(newVal) dep.notify() } }) GETTERS/SETTERS! https://github.com/vuejs/vue/blob/v2.5.16/src/core/observer/index.js#L156
  7. Vue Reactivity https://speakerdeck.com/jeffschenck/vue-reactivity-learning-by-accident BUT WAIT............................ export default { data ()

    { return { todos: ['eat', 'sleep', 'vue'], } }, methods: { addTodo () { this.todos.push('more vue') }, }, }
  8. Vue Reactivity https://speakerdeck.com/jeffschenck/vue-reactivity-learning-by-accident PATCHED ARRAY METHODS! // Totally patched arr.push(...)

    arr.pop(...) arr.shift(...) arr.unshift(...) arr.splice(...) arr.sort(...) arr.reverse(...) // Totally NOT patched // ...because you totally can't arr[i] = ... arr.length = ... https://github.com/vuejs/vue/blob/v2.5.16/src/core/observer/array.js#L11
  9. Vue Reactivity https://speakerdeck.com/jeffschenck/vue-reactivity-learning-by-accident export default { data () { return

    { todos: ['eat', 'sleep', 'vue'], } }, methods: { updateTodo () { this.$set(this.todos, 0, 'coffee') }, }, } <button @click="updateTodo()"> Update </button> <ul> <li v-for="todo in todos"> {{ todo }} </li> </ul> TOTALLY FIXED WORKING CODE
  10. Vue Reactivity https://speakerdeck.com/jeffschenck/vue-reactivity-learning-by-accident export default { methods: { focusInput ()

    { this.$refs.focus() }, }, } <button @click="focusInput()"> Focus </button> <input ref="input"> TOTALLY WORKING CODE
  11. Vue Reactivity https://speakerdeck.com/jeffschenck/vue-reactivity-learning-by-accident export default { data () { return

    { shown: false, } }, methods: { showInput () { this.shown = true this.$refs.input.focus() }, }, } <button @click="showInput()"> Show + Focus </button> <input v-if="shown" ref="input"> TOTALLY NOT WORKING CODE https://codepen.io/jeffschenck/pen/aYELPY
  12. Vue Reactivity https://speakerdeck.com/jeffschenck/vue-reactivity-learning-by-accident export default { data () { return

    { shown: false, } }, methods: { showInput () { this.shown = true this.$nextTick(() => { this.$refs.input.focus() }) }, }, } <button @click="updateTodo()"> Update </button> <ul> <li v-for="todo in todos"> {{ todo }} </li> </ul> TOTALLY FIXED WORKING CODE