Vue Composition API Workshop
@akryum
Vue.js Core Team
Why the Composition API?
Why the Composition API?
Component readability as it grows
Code Reusing Patterns have drawbacks
Limited TypeScript support
Vue 2 Limitations:
export default {
data () {
return {
searchText: '',
}
},
computed: {
filteredItems () {
// ...
},
},
}
Component readability as it grows
Search ▶
Search ▶
export default {
data () {
return {
searchText: '',
sortBy: 'name',
}
},
computed: {
filteredItems () {
// ...
},
sortedItems () {
// ...
},
},
}
Component readability as it grows
Search ▶
Search ▶
Sort ▶
Sort ▶
Features are organized by component options
Organized by component options
Organized by features
With the Composition API
export default {
data () {
return {
searchText: '',
sortBy: 'name',
}
},
computed: {
filteredItems () {
// ...
},
sortedItems () {
// ...
},
},
}
Search ▶
Search ▶
Sort ▶
Sort ▶
With the Composition API
Search ▶
Sort ▶
export default {
setup () {
// Search feature
const searchText = ref('')
const filteredItems = computed(() => /* ... */)
// Sort feature
const sortBy = ref('name')
const sortedItems = computed(() => /* ... */)
},
}
With the Composition API
Search ▶
Sort ▶
export default {
setup () {
// Search feature
const searchText = ref('')
const filteredItems = computed(() => /* ... */)
// Sort feature
const sortBy = ref('name')
const sortedItems = computed(() => /* ... */)
},
}
Organized by feature
With the Composition API
Search ▶
Sort ▶
export default {
setup () {
// Search feature
const searchText = ref('')
const filteredItems = computed(() => /* ... */)
// Sort feature
const sortBy = ref('name')
const sortedItems = computed(() => /* ... */)
return {
searchText,
sortBy,
sortedItems,
}
},
}
With the Composition API
Search ▶
Sort ▶
export default {
setup () {
// Search feature
const searchText = ref('')
const filteredItems = computed(() => /* ... */)
// Sort feature
const sortBy = ref('name')
const sortedItems = computed(() => /* ... */)
return {
searchText,
sortBy,
sortedItems,
}
},
}
Expose to the template
With the Composition API
Search ▶
Sort ▶
export default {
setup () {
const { searchText, filteredItems } = useSearch()
const { sortBy, sortedItems } = useSort(filteredItems)
return {
searchText,
sortBy,
sortedItems,
}
},
}
// Search feature
function useSearch (items) {
const searchText = ref('')
const filteredItems = computed(() => /* ... */)
return { searchText, filteredItems }
}
// Sort feature
function useSort (items) {
const sortBy = ref('name')
const sortedItems = computed(() => /* ... */)
return { sortBy, sortedItems }
}
With the Composition API
Search ▶
Sort ▶
export default {
setup () {
const { searchText, filteredItems } = useSearch()
const { sortBy, sortedItems } = useSort(filteredItems)
return {
searchText,
sortBy,
sortedItems,
}
},
}
// Search feature
function useSearch (items) {
const searchText = ref('')
const filteredItems = computed(() => /* ... */)
return { searchText, filteredItems }
}
// Sort feature
function useSort (items) {
const sortBy = ref('name')
const sortedItems = computed(() => /* ... */)
return { sortBy, sortedItems }
}
Extract features into Composition Functions
Vue 2
Code Reuse Patterns have drawbacks
Vue 2 Code Reuse Patterns
Mixins
Mixin Factories
Scoped Slots
Mixins
export default {
data () {
return {
searchText: '',
sortBy: 'name',
}
},
computed: {
filteredItems () {
// ...
},
sortedItems () {
// ...
},
},
}
Mixins
const searchMixin = {
data () {
return { searchText: '' }
},
computed: {
filteredItems () { /* ... */ },
},
}
const sortMixin = {
data () {
return { sortBy: 'name' }
},
computed: {
sortedItems () { /* ... */ },
},
}
export default {
mixins: [ searchMixin, sortMixin ],
}
Mixins
const searchMixin = {
data () {
return { searchText: '' }
},
computed: {
filteredItems () { /* ... */ },
},
}
const sortMixin = {
data () {
return { sortBy: 'name' }
},
computed: {
sortedItems () { /* ... */ },
},
}
export default {
mixins: [ searchMixin, sortMixin ],
}
Organized by feature
Conflict Prone
Unclear relationships
Not easily reusable
Mixin Factories
Functions that return a mixin
Mixin Factories
function searchMixinFactory ({ ... }) {
return {
data () {
return { searchText: '' }
},
computed: {
filteredItems () { /* ... */ },
},
}
}
function sortMixinFactory ({ ... }) {
return {
data () {
return { sortBy: 'name' }
},
computed: {
sortedItems () { /* ... */ },
},
}
}
export default {
mixins: [ searchMixinFactory(), sortMixinFactory() ],
}
Mixin Factories
function searchMixinFactory ({ ... }) {
return {
data () {
return { searchText: '' }
},
computed: {
filteredItems () { /* ... */ },
},
}
}
function sortMixinFactory ({ ... }) {
return {
data () {
return { sortBy: 'name' }
},
computed: {
sortedItems () { /* ... */ },
},
}
}
export default {
mixins: [ searchMixinFactory(), sortMixinFactory() ],
}
Organized by feature
Weak namespacing
Implicit property addition
No instance access to customize the behavior
Reusable & configurable
Clearer relationship
Scoped slots
Scoped slots
<script>
export default {
// Search feature here
}
</script>
<template>
<div>
<slot v-bind="{ searchText, filteredItems }" />
</div>
</template>
<script>
export default {
// Sort feature here
}
</script>
<template>
<div>
<slot v-bind="{ sortBy, sortedItems }" />
</div>
</template>
<SearchService
v-slot="searchProps"
>
<SortService
:item="searchProps.filteredItems"
v-slot="sortProps"
>
<li v-for="item of sortProps.sortedItems">
...
</li>
</SearchService>
</SearchService>
SearchService.vue
SortService.vue
Scoped slots
<script>
export default {
// Search feature here
}
</script>
<template>
<div>
<slot v-bind="{ searchText, filteredItems }" />
</div>
</template>
<script>
export default {
// Sort feature here
}
</script>
<template>
<div>
<slot v-bind="{ sortBy, sortedItems }" />
</div>
</template>
<SearchService
v-slot="searchProps"
>
<SortService
:item="searchProps.filteredItems"
v-slot="sortProps"
>
<li v-for="item of sortProps.sortedItems">
...
</li>
</SearchService>
</SearchService>
Solves mixin problems
Increased indentation
Lost of configuration
Less flexible
Less performant
Composition API
Composition API
export default {
data () {
return {
searchText: '',
sortBy: 'name',
}
},
computed: {
filteredItems () {
// ...
},
sortedItems () {
// ...
},
},
}
Composition API
export default {
setup () {
const { searchText, filteredItems } = useSearch()
const { sortBy, sortedItems } = useSort(filteredItems)
return {
searchText,
sortBy,
sortedItems,
}
},
}
// Search feature
function useSearch (items) {
const searchText = ref('')
const filteredItems = computed(() => /* ... */)
return { searchText, filteredItems }
}
// Sort feature
function useSort (items) {
const sortBy = ref('name')
const sortedItems = computed(() => /* ... */)
return { sortBy, sortedItems }
}
Composition API
export default {
setup () {
const { searchText, filteredItems } = useSearch()
const { sortBy, sortedItems } = useSort(filteredItems)
return {
searchText,
sortBy,
sortedItems,
}
},
}
// Search feature
function useSearch (items) {
const searchText = ref('')
const filteredItems = computed(() => /* ... */)
return { searchText, filteredItems }
}
// Sort feature
function useSort (items) {
const sortBy = ref('name')
const sortedItems = computed(() => /* ... */)
return { sortBy, sortedItems }
}
Less code
Familiar functions
Extremely flexible
Tooling friendly
Advanced syntax
Workshop
Time
Movie DB
Movie DB
Movie DB
Client
Vue
Apollo Client
Server
Node
GraphQL
Apollo Server
Let's build this!
@Akryum
Thank you!
Workshop Summit 2020 - Vue Composition API and GraphQL
By Guillaume Chau
Workshop Summit 2020 - Vue Composition API and GraphQL
- 5,490