Composition API:

quick overVue

Important warning!

"...and progressively migrate away from deprecated options, until eventually switching to the standard build"

"...and progressively migrate away from deprecated options, until eventually switching to the standard build"

"Current Syntax to be deprecated"

"Composition functions will eventually be the only way to build Vue components"

Reddit

Composition API is

purely additive

Natalia Tepluhina

Staff Frontend Engineer

Core Team Member

Google Dev Expert

Why do we need

a new API?

@N_Tepluhina

export default {
  data() {
    return {
      breedSearch: {
        query: '',
        results: []
      }
    }
  },
  methods: {
    runBreedSearch() {
      this.$axios
        .get(this.breedEndpoint, {
          params: {
            limit: 8,
            q: this.breedSearch.query
          }
        })
        .then(res => {
          this.breedSearch.results = res.data.filter(breed => breed.description)
        })
    }
  },
}

@N_Tepluhina

export default {
  data() {
    return {
      ...
        
      resultSorting: {
        options: [
          ['energy_level', 'desc'],
          ['affection_level', 'desc'],
          ['dog_friendly', 'desc']
        ],
        selectedOptionIndex: 0
      }
    }
  },
  computed: {
    sortedResults() {
      const selectedOption = this.resultSorting.options[
        this.resultSorting.selectedOptionIndex
      ]
      return orderBy(this.productSearch.results, ...selectedOption)
    }
  },
}

@N_Tepluhina

One component

Two features

@N_Tepluhina

  data() {
    return {
      breedSearch: {
        query: '',
        results: []
      },
      resultSorting: {
        options: [
          ['energy_level', 'desc'],
          ['affection_level', 'desc'],
          ['dog_friendly', 'desc']
        ],
        selectedOptionIndex: 0
      }
    }
  },
  computed: {
    sortedResults() {
      const selectedOption = this.resultSorting.options[
        this.resultSorting.selectedOptionIndex
      ]
      return orderBy(this.breedSearch.results, ...selectedOption)
    }
  },
  methods: {
    runBreedSearch() {
      this.$axios
        .get(this.breedEndpoint, {
          params: {
            limit: 8,
            q: this.breedSearch.query
          }
        })
        .then(res => {
          this.breedSearch.results = res.data.filter(breed => breed.description)
        })
    }
  },

@N_Tepluhina

How to compose reusable features?

@N_Tepluhina

Option 1

Mixins

@N_Tepluhina

const breedSearchMixin = {
  data() {
    return {
      breedSearch: {
        query: '',
        results: []
      }
    }
  },
  methods: {
    runBreedSearch() {
      this.$axios
        .get(this.breedEndpoint, {
          params: {
            limit: 8,
            q: this.breedSearch.query
          }
        })
        .then(res => {
          this.breedSearch.results = res.data.filter(breed => breed.description)
        })
    }
  }
}

@N_Tepluhina

const breedSortingMixin = {
  data() {
    return {
      resultSorting: {
        options: [
          ['energy_level', 'desc'],
          ['affection_level', 'desc'],
          ['dog_friendly', 'desc']
        ],
        selectedOptionIndex: 0
      }
    }
  },
  computed: {
    sortedResults() {
      const selectedOption = this.resultSorting.options[
        this.resultSorting.selectedOptionIndex
      ]
      return orderBy(this.breedSearch.results, ...selectedOption)
    }
  }
}

@N_Tepluhina

const breedSearchMixin = {
  data() {
    return {
      breedSearch: {
        query: '',
        results: []
      }
    }
  },
  methods: {
    runBreedSearch() {
      this.$axios
        .get(this.breedEndpoint, {
          params: {
            limit: 8,
            q: this.breedSearch.query
          }
        })
        .then(res => {
          this.breedSearch.results = res.data.filter(breed => breed.description)
        })
    }
  }
}

const breedSortingMixin = {
  data() {
    return {
      resultSorting: {
        options: [
          ['energy_level', 'desc'],
          ['affection_level', 'desc'],
          ['dog_friendly', 'desc']
        ],
        selectedOptionIndex: 0
      }
    }
  },
  computed: {
    sortedResults() {
      const selectedOption = this.resultSorting.options[
        this.resultSorting.selectedOptionIndex
      ]
      return orderBy(this.breedSearch.results, ...selectedOption)
    }
  }
}

export default {
  mixins: [productSearchMixin, resultSortingMixin]
}

@N_Tepluhina

👎 Not really reusable

👎 Conflict-prone

👎 Unclear source

@N_Tepluhina

Option 2

Scoped slots

@N_Tepluhina

<template>
  <GenericSearch :get-results="runBreedSearch" v-slot="breedSearch">
    <input
      :value="breedSearch.query"
      @input="breedSearch.set($event.target.value)"
      @keyup.enter="breedSearch.run"
    />
    <BreedCard
      v-for="breed in breedSearch.results"
      :key="breed.id"
      :breed="breed"
    />
  </GenericSearch>
</template>

@N_Tepluhina

👎 Not flexible

👎 Less performant

@N_Tepluhina

So, what's the option?

@N_Tepluhina

New Composition API

@N_Tepluhina

Demo

@N_Tepluhina

bit.ly/comp-api-demo

@N_Tepluhina

Thank you!

@N_Tepluhina