Vue.js Composition API

Продолжая разбирать тему повторного использования кода Vue.js, я пришел к Composition API, который является основным новшеством Vue 3. Его также можно использовать во 2 версии Vue, если установить как отдельный пакет. В сети эти изменения вызвали бурное обсуждение, зачастую негодование, среди тех, кто пользуется данным фреймворком и  создал не мало кода на старом API (Options API). Давайте разберемся почему появился новый API, как его использовать и в чем его плюсы.

Как я показал ранее в Vue для повторного использования кода существуют mixin-ы (и опция extends, которая работает так же). Но если вы использовали их ранее, то должны были заметить некоторые проблемы с ними связанные. А именно можно выделить такие вещи, как

  • коллизии имен методов и свойств
  • неявные зависимости

Коллизиями имен — существование в  2 или более mixin-ах свойств и методов с одинаковыми именами. Когда происходит такое,  то один метод просто заменяет другой следуя политике слияния (которые можно переопределять, но это не очень удобно и читаемо).

Неявные зависимости — это, например, использование в методах mixin-а свойств, которые не объявлены в нем самом, а присутствуют, скажем, в компоненте, использующем этот mixin. При внесении изменений надо или помнить или смотреть откуда появляется данная переменная.

Это проблемы делают код менее читаемым и предсказуемым. И это становится еще большей проблемой, когда мы используем не только свои, но и mixin-ы из сторонних пакетов.

Новый Composition API решает эти проблемы. В предыдущей статье был компонент Mix.vue, где использовались mixin-ы, которые в своих методах оперируют свойством компонента. Я реализовал это через новый API, объясняю код и показываю как решились 2 проблемы, описанные выше.

 

<template>
  <div class="component-border pl-1 mb-1 ms-1">
    <h1>
      Example Composition API
    </h1>
    <div>
      <p>Count: {{ count }}</p>
      <p>
        <button
          v-for="(action, index) in actions"
          v-bind:key="index"
          @click="action.handler"
          class="me-1">
          {{ action.text }}
        </button>
      </p>
    </div>
  </div>
</template>
<script>
import { ref } from '@vue/composition-api';
import useIncrement from "../briks/useIncrement";
import useDecrement from "../briks/useDecrement";

export default {
  setup: () => {

    const count = ref(0);
    const { increment } = useIncrement(count);
    const { decrement } = useDecrement(count);

    function clear() {
      count.value = 0;
    }

    const actions = ref([
      { text: 'Increment', handler: increment },
      { text: 'Decrement', handler: decrement },
      { text: 'Clear', handler: clear },
    ]);

    return {
      actions,
      count,
      increment,
      clear,
      decrement
    }
  },
};
</script>

const count = ref(0); — это объявление реактивного свойства в Composition API. А clear() — метод компонента, который устанавливает это свойство в 0. При этом приходится обращаться к величине через синтаксис count.value. В шаблоне, однако это не требуется. actions — тоже реактивное свойство.

Но самое интересное, это — использование методов, которые добавлены в компонент из отдельных файлов:

import useIncrement from "../briks/useIncrement";
import useDecrement from "../briks/useDecrement";
...
const { increment } = useIncrement(count);
const { decrement } = useDecrement(count);

Это и есть замена миксинов. И здесь, чтобы зависимость стала явной, свойство count передано как параметр в обе функции.

export default function(count) {

  function increment() {
    count.value++;
  }

  return {
    increment,
  }
}

Таким образом решена проблема неявных зависимостей. Все зависимости становятся явными. По коду видно, что это внешняя величина.

При подключении методов в компонент мы можем задать задать им произвольные имена (смотрите в фигурных скобках).

const { increment } = useIncrement(count);
const { decrement } = useDecrement(count);

Правда в данном случае имена остались теми же, но вы вольны изменить это. Например, изменить имена на inc и dec,  используя возможности деструктурирующего присваивания:

const { increment: inc } = useIncrement(count);
const { decrement: dec } = useDecrement(count);

И в конечном итоге все, что будет использоваться в шаблоне нужно вернуть

return {
  actions,
  count,
  increment,
  clear,
  decrement
}

Здесь снова видим подход, при котором все делается явно.

Как мы видим обе проблемы прекрасно решены в новом Composition API.

Примеси в старом Options API позволяли получить нечто вроде наследования (на самом деле они мне напоминаю traits в php), в то время как в новом Composition API мы получает композицию. В различной литературе по архитектуре программ можно часто встретить фразу: «Предпочитайте композицию наследованию«. Теперь во Vue.js больше возможности следовать этой рекомендации.

Vue.js снова становится лучше. Вот цитата пользователя с habr:

Хмм… это только мне кажется, или у Vue и React такое развитие, что сначала в React сделают крутую фичу, а потом Vue сделают себе то же, но намного круче, как на примере с хуками/Composition API?

А что вы об этом думаете? Пишите в комментариях ваши ценные мысли.

PS. Конечно возможности нового API шире. Чтобы углубить знания придется обратиться к документации. А после этого нужную функцию можно искать в шпаргалке.


Код примеров — в моем репозитории

Использованные материалы:

Leave a Reply

Ваш адрес email не будет опубликован. Обязательные поля помечены *