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
- 6,924
 
   
   
  