Vue 3 y Composition API
A patear el tablero
Vue 3 y Composition API
π―π 3οΈβ£
π¦ @ianaya89
π¦π· Nacho Anaya
π¦ @ianaya89
- π Principal Engineer @BalloonPlatform
- π¨βπ Ambassador @Auth0 & @GitKraken
- π£ Tech Speaker @MozTechSpeakers
- π Organizador @Vuenos_Aires
π¨
π vue-next
π€ πββοΈ π€―
Smaller + Faster + Easier
0οΈβ£ Re-escrito
π Simple y ExplΓcito
π Performance
~120% mas rΓ‘pido
π Monorepo
π Paquetes Individuales
<br> # β Extensible
<br> # π³ Tree-Shakeable
Global API
π 10 KB gzipped
v2.x ~20 KB
<br> # π© TypeScript
π Global Mounting
import { createApp } from 'vue'
import App from './App.vue'
const app = createApp(App)
app.use(/* ... */)
app.mixin(/* ... */)
app.component(/* ... */)
app.directive(/* ... */)
app.mount('#app')
β’οΈ Reactivity Engine
- π
Object.defineProperty()
- π
Proxy
β’οΈ π Antes (2.x)
<script>
export default {
data () {
return {
object: { name: 'Nacho' },
array: ['string']
}
},
created () {
this.$set(this.object, 'lastName', 'Anaya')
this.$delete(this.object, 'lastName')
this.$set(this.array, 1, 'new string')
}
}
</script>
β’οΈ π Antes (2.x)
<script>
export default {
data () {
return {
object: { name: 'Nacho' },
array: ['string']
}
},
created () {
this.$set(this.object, 'lastName', 'Anaya')
this.$delete(this.object, 'lastName')
this.$set(this.array, 1, 'new string')
}
}
</script>
β’οΈ π Ahora (3.x)
<script>
export default {
data () {
return {
object: { name: 'Nacho' },
array: ['string']
}
},
created () {
this.object.lastName = 'Anaya'
delete this.object.lastName
this.array[1] = 'new string'
}
}
</script>
β’οΈ π Ahora (3.x)
π "Reactivity Caveats"
β’οΈ π Ahora (3.x)
Map
- Set
- WeakMap
- WeakSet
π Multiples v-model
<LoginForm
v-model:email="email"
v-model:password="password"
v-model:rememberMe="rememberMe"
/>
π° Fragments
πΈ Multiples Root Elements
<template>
<div>...</div>
<div>...</div>
</template>
π³ Portals
<Portal target="#my-portal" />
π³ Portals
<!-- App.vue -->
<template>
<main>
<router-view />
<div id="my-portal"></div>
</main>
</template>
π³ Portals
<!-- Other.vue -->
<template>
<main>
<h1>Hola!</h1>
<Portal target="#my-portal">
<p>Este es el contenido del Portal<\p>
</Portal>
</main>
</template>
πͺ Suspense
<Suspense>
<template #default>
<UserList />
<template>
<template #fallback>
<p>Loading...</p>
</template>
</Suspense>
π£
πΊπΏπΊπΏπΊπΏπΊπΏ β°οΈ Class API
πΊπΏπΊπΏπΊπΏπΊπΏ β°οΈ Function API
Ξ» π¦ Composition API
π¦
π¦π¦
π¦π¦π¦
Ζ Composicion flexible basada en funciones
π Reactivity API
π Reactivity API
import { ref } from 'vue'
const num = ref(0)
console.log(num.value)
const increment = () => (num.value += 1)
document.body.addEventListener('click', increment)
π Reactivity API
import { ref, watchEffect } from 'vue'
const num = ref(0)
const increment = () => (num.value += 1)
document.body.addEventListener('click', increment)
watchEffect(() => (
document.body.innerHTML = `num is ${num.value}`
))
π Reactivity API
import { reactive, computed } from 'vue'
const state = reactive({
count: 1,
double: computed(() => state.count * 2)
})
π Hello Vue3!
setup(props, context)
<template>
<h1>Num is {{ num }}</h1>
<button @click="increment">+</button>
</template>
<script>
import { ref } from 'vue'
export default {
setup() {
const num = ref(0)
const increment = () => (num.value += 1)
return { num, increment }
}
}
</script>
π Hello Vue3!
<template>
<div>
<child-component :name="Nacho" />
</div>
</template>
π Hello Vue3!
<template>
<div>
<h1>Hola {{ name }}!</h1>
</div>
</template>
<script>
export default {
props: { name: String },
setup(props, context) {
const { name } = props
return { name }
}
}
</script>
π Hello Vue3!
export default {
setup(props, context) {
console.log(props)
context.attrs
context.slots
context.refs
context.emit
context.parent
context.root
}
}
β»οΈ Dynamic Lifecycle Injection
β»οΈ Dynamic Lifecycle Injection
import { onMounted, onUpdated } from 'vue'
export default {
setup () {
onMounted(() => console.log('Mounted'))
onUpdated(() => console.log('Updated'))
}
}
β»οΈ Dynamic Lifecycle Injection
import { onMounted } from 'vue'
export default {
setup () {
// attachar un hook para otro componente
onMounted(() => console.log('Mounted...'), otherComponent)
}
}
πββοΈ MotivaciΓ³n
- Escalabilidad
- Inferencia de Tipos
- Organizacion
- Performance
- πLogic Compositionπ
π¦π¦π¦ Logic Composition
π Patrones Actuales
- Mixins
- HOC
- Renderless Components
π¦ Logic Composition
import { ref, onMounted, onUnmounted } from 'vue'
export default function useMousePosition() {
const x = ref(0)
const y = ref(0)
function updatePosition(e) {
x.value = e.pageX
y.value = e.pageY
}
onMounted(() => window.addEventListener('mousemove', updatePosition))
onUnmounted(() => window.removeEventListener('mousemove', updatePosition))
return { x, y }
}
π¦ Logic Composition
<template>
<div>Position {{ x }} {{ y }}</div>
</template>
<script>
import useMousePosition from './useMousePosition'
import useOtherLogic from './useOtherLogic'
export default {
setup() {
const { x, y } = useMousePosition()
const other = useOtherLogic()
return { x, y, other }
}
}
</script>
π SE ROMPE TODO!
πΎ NO SE ROMPE NADA!
Composition API
π€
Options API
β Composition API
- Aplicaciones / componentes grandes
- Equipos grandes
- Compartir / reusar codigo
- Soporte TS
π¨βπ» Como usarlo?
<br>$ vue create my-app
$ vue add vue-next