Superfast Introduction to Vue 3
Praveen Puglia

@praveenpuglia
praveenpuglia.com
@vuehyd
hyd.vue.community






The Struggle
Reactivity
Reactivity
let internalValue = data.name;
const dep = new Dep();
Object.defineProperty(data, 'name', {
  get() {
    // name is accessed.
    dep.depend();
    return internalValue;
  },
  set(newVal) {
    // name is updated.
    internalValue = newVal;
    dep.notify();
  }
});
export default {
  data() {
    name: "Vue Hyderabad"
  },
  computed: {
    message() {
      return `Hello! ${this.name}`;
    }
  }
}👎 Reactivity caveats
Cannot detect changes to array items or object property value changes
Cannot declare reactive properties later...sort of!
var vm = new Vue({
  data: {
    a: 1
  }
})
// `vm.a` is now reactive
vm.b = 2
// `vm.b` is NOT reactive// Array item update via [index] notation
vm.items[indexOfItem] = newValue
// Add or remove a property in an object
delete vm.user.firstName
vm.user.age = 28😕 Half baked solutions
Cannot detect changes to array items or object property value changes
Cannot declare reactive properties later...sort of!
// Can't add to root level anymore
// But we can in nested object.
Vue.set(vm.someObject, 'b', 2)Vue.set(vm.items, indexOfItem, newValue)Go Immutable
Code organization
const vm = new Vue({
  props: {...},
  data() {...},
  methods: {...},
  computed: {...},
  filters: {...},
  watch: {...},
  created() {...},
  mounted() {...},
  ...,
  ...
})Code 😳r...MESS
const vm = new Vue({
  props: {
  },
  data() {
  },
  methods: {
  },
  computed: {
  },
  filters: {
  },
  watch: {
  },
  created() {
  },
  mounted() {
  }
})TypeScript
- Large projects and teams
 - Make the most out of GraphQL Stack
 - Better tooling, IDE support
 - All the benefits of a Type System.
 
TypeScript IN VUE
- Vue was never built using TypeScript or for it.
 - A lot of magic happens on `this`, the Vue instance.
 - Large objects aren't really that type friendly, such as the Options API
 - Makes it hard to work with Plugins, Third Party components / tools.
 
👎 Half baked solutions
import { Vue, Component, Prop } from "vue-property-decorator";
@Component
export default class AwesomeComponent extends Vue {
  @Prop({
    type: Boolean
  })
  isStupid!: boolean;
  dataProperty = 'This is reactive';
  anotherDataProperty = 'This is reactive too';
  get computedValue() {...}
  
  created() {...}
}The Relief
It's Not GOING To BE LIKE ANGULAR
New apis are purely opt-in
REACTIVITYÂ
USING PROXIES
const target = {};
const targetProxy = new Proxy(target, {
  get: function(theTarget, prop) {
    return prop === 'age' ? 
      `Your age is ${theTarget[prop]} years` 
      : theTarget[prop];
  }
});
target.age = 20
target.age // 20
targetProxy.age // Your age is 20 years- Double the speed, immediately
 - Half the memory footprint
 - No need of Vue.set or patching Array.prototype.push / pop
 - You get the benefits for free
 
REACTIVITYÂ
USING PROXIES

vueschool.io
API
COMPOSITION
- 
All the time people had spent learning Vue had been wasted given everything was about to change.
 - 
The Vue Core team had suddenly implemented a huge breaking change without any consultation.
 - 
Vue is turning into React!
 - 
No, Vue is turning into AngularJS/Angular!
 - All HTML now needs to be written as a giant string!
 

- Completely Opt-in
 - You don't need to rewrite your entire codebase
 - The entire changes went through an RFC process
 
API
COMPOSITION
import { reactive } from 'vue'
const state = reactive({
  count: 0
})import { reactive, watch } from 'vue'
const state = reactive({
  count: 0
})
watch(() => {
  document.body.innerHTML = `count is ${state.count}`
})new Vue({
  data() {
    return {
      count: 0
    }
  }
})import { reactive, watch } from 'vue'
const state = reactive({
  count: 0
})
function increment() {
  state.count++
}
const renderContext = {
  state,
  increment
}
watch(() => {
  // hypothetical internal code, NOT actual API
  renderTemplate(
    `<button @click="increment">{{ state.count }}</button>`,
    renderContext
  )
})API
COMPOSITION
import { reactive, computed } from 'vue'
const state = reactive({
  count: 0
})
const double = computed(() => state.count * 2)
// Access computed
console.log(double.value)<!-- Automatic Ref Unwrapping -->
{{ double }}API
COMPOSITION
<template>
  <button @click="increment">
    Count is: {{ state.count }}, 
    double is: {{ state.double }}
  </button>
</template><script>
import { reactive, computed } from 'vue'
export default {
  setup() {
    const state = reactive({
      count: 0,
      double: computed(() => state.count * 2)
    })
    function increment() {
      state.count++
    }
    return {
      state,
      increment
    }
  }
}
</script>API
COMPOSITION
<script>
import { reactive, computed } from 'vue';
import { useCounter } from '@/utils';
export default {
  setup() {
    const {state, increment} = useCounter();
    return {
      state,
      increment
    }
  }
}
</script>WHY DO ALL THIS?
API
COMPOSITION
Extracting logic and much better composition & reuse.
useSearch() useSort() usePagination() useIntersectionObserver() useLocalStorage() ... vue-use-web
API
COMPOSITION
- Be able to use Vue's reactivity system without a Vue instance
 - Much wider application area
 - Tree-shaken internals for smaller builds
 - Much improved TS support because of internals being mere functions
 - Plugins without polluting global Vue object.
 
API
COMPOSITION

VDom rewrite
<div>
  <p>This is static</p>
  <p>This is static as well</p>
  <p>This is {{dynamicVariable}}</p>
  <p>This is static after dynamic</p>
</div>Before
Re-render everything, even the static parts.
After
Only re-renders the paragraph at line 4. Static parts get hoisted and never trigger changes
VDom rewrite
Monomorphic VNode Creation
function add(a: any, b: any) {
  return a + b;
}
add(1, 2) // 3
add('a', 'b') // abfunction add(a: number, b: number) {
  return a + b;
}
function concat(a: string, b: string) {
  return a + b;
}
add(1, 2) // 3
concat('a', 'b') // abMultiple root nodes
<template>
  <li v-for="item of items" :key="item.id">
    <icon :name="item.icon"></icon>{{item.title}}
  </li>
</template>Component template should contain exactly one root element. If you are using v-if on multiple elements, use v-else-if to chain them instead.
Vue 2
Vue 3
- 
	
v-if
 - 
	
v-for
 - multiple nodes
 - works for any component
 
SIMPLER custom inputs
<BaseInput
  placeholder="John Doe"
  label="First Name"
  v-model="firstName"
  @input="handleFirstName"
/><template>
  <label>
    {{ label }}
    <input
      v-bind="$attrs"
      v-on="$listeners"
      @input="$emit('input', $event.target.value)"
    />
  </label>
</template>
<script>
export default {
  props: ["label"],
  inheritAttrs: false
};
</script>SIMPLER custom inputs
<BaseInput
  placeholder="John Doe"
  label="First Name"
  v-model="firstName"
  @input="handleFirstName"
/><template>
  <label>
    {{ label }}
    <input
      v-bind="$attrs" />
  </label>
</template>
<script>
export default {
  props: ["label"]
};
</script>Everything is $attrs
- 
Events : v-on:input => on-input
 - 
v-model : value / on-update:value
 - Multiple v-model : v-model:startDate, v-model:endDate
 
<InviteeForm
  v-model:name="inviteeName"
  v-model:email="inviteeEmail"
/><DatePicker
  v-model:startDate="startDate"
  v-model:endDate="endDate"
/>And there's More
- In Built Portals
 - All slots are scoped slots & compiled as functions
 - New custom directives API
 - Suspense
 - Improved native support
 - Thorough migration guide
 
READ ON
- 
https://vueschool.io/articles/vuejs-tutorials/exciting-new-features-in-vue-3/
 - 
https://vue-composition-api-rfc.netlify.com/
 - 
https://www.vuemastery.com/courses/vue-3-essentials/why-the-composition-api/
 - 
https://vueschool.io/articles/vuejs-tutorials/faster-web-applications-with-vue-3/
 - https://alligator.io/vuejs/common-gotchas/
 
Praveen Puglia

@praveenpuglia
praveenpuglia.com
@vuehyd
hyd.vue.community






Superfast Introduction to Vue 3
By Praveen Puglia
Superfast Introduction to Vue 3
- 1,595