Looking into the Vueture:

Composition Functions

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" (c) Reddit

Composition API is

purely additive

Natalia Tepluhina

Senior Frontend Engineer

Core Team Member

Google Dev Expert

Why do we need

a new API?

@N_Tepluhina

@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

<GenericSearch
    :get-results="runBreedSearch"
    v-slot="breedSearch"
>
  {{ breedSearch.query }}
</GenericSearch>

@N_Tepluhina

<script>
export default {
  props: ['getResults'],
  data() {
    return {
      query: '',
      results: []
    }
  },
  methods: {
    run() {
      this.results = []
      this.getResults(this.query).then(results => {
        this.results = results
      })
    },
    set(value) {
      this.query = value
    }
  }
}
</script>

@N_Tepluhina

<template>
  <div>
    <slot v-bind="{ query, results, run, set }"/>
  </div>
</template>

@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

const count = ref(0)
{
  value: 0
}

Refs

@N_Tepluhina

Refs vs. Reactive

// style 1: separate variables

let x = 0
let y = 0

function updatePosition(e) {
  x = e.pageX
  y = e.pageY
}

@N_Tepluhina

Refs vs. Reactive

// style 2: single object

const pos = {
  x: 0,
  y: 0
}

function updatePosition(e) {
  pos.x = e.pageX
  pos.y = e.pageY
}

@N_Tepluhina

bit.ly/composition-api

@N_Tepluhina

bit.ly/comp-api-demo

@N_Tepluhina

Thank you!

Vue Composition API

By Natalia Tepluhina

Vue Composition API

New Vue 3 function-based API: why, where and when

  • 575

More from Natalia Tepluhina