mrssea

10 ошибок, которых следует избегать при работе с Vue 3

Vue 3 уже довольно давно работает стабильно. Многие используют его в продакшене, и всем остальным в конечном итоге придется мигрировать. У меня была возможность поработать с ним и понять, какие ошибки я допускаю, которые вы наверняка хотели бы избежать.

1. Использование Reactive для объявления примитивов

Декларирование данных раньше было простым, но теперь стали доступны несколько помощников. Главное правило сейчас:

Использовать reactive для Object, Array, Map, Set

Использовать ref для String, Number, Boolean

Использование reactive для примитива приведет к warning, и значение не будет реактивным.

/* НЕ БУДЕТ РАБОТАТЬ КАК ОЖИДАЛОСЬ */
<script setup>
import { reactive } from "vue";

const count = reactive(0);
</script>

[Vue warn]: value cannot be made reactive

Можете попробовать тут

Удивительно то, что наоборот работает! Например, использование ref для объявления Array вызовет вместо этого внутренний вызов reactiveПодробнее о ref и reactive во Vue 3

2. Деструктуризация реактивного значения

Деструктуризация (destructuring assignment) – это особый синтаксис присваивания, при котором можно присвоить массив или объект сразу нескольким переменным, разбив его на части.

Давайте представим, что у вас есть реактивный объект со счетчиком и кнопкой для его увеличения.

<template>
  Counter: {{ state.count }}
  <button @click="add">Increase</button>
</template>

<script>
import { reactive } from "vue";
export default {
  setup() {
    const state = reactive({ count: 0 });

    function add() {
      state.count++;
    }

    return {
      state,
      add,
    };
  },
};
</script>

Довольно просто и работает так, как ожидалось, но у вас может возникнуть соблазн использовать деструктуризацию и сделать следующее.

/* Работает не так, как ожидалось */
<template> 
  <div>Counter: {{ count }}</div>
  <button @click="add">Increase</button>
</template>

<script>
import { reactive } from "vue";
export default {
  setup() {
    const state = reactive({ count: 0 });

    function add() {
      state.count++;
    }

    return {
      ...state,
      add,
    };
  },
};
</script>

попробовать 

Код выглядит также и, судя по нашему предыдущему опыту, должен работать, но на самом деле отслеживание реактивности Vue работает над доступом к свойствам. Это означает, что мы не можем присвоить или деструктурировать реактивный объект, потому что связь реактивности с первой ссылкой потеряна. Это одно из ограничений использования реактивного помощника.

3. Запутаться с .value

Аналогично, к одной из особенностей использования ref может быть трудно привыкнуть.

Ref принимает значение и возвращает реактивный объект. Значение доступно внутри объекта в свойстве .value

const count = ref(0)

console.log(count) // { value: 0 }
console.log(count.value) // 0

count.value++
console.log(count.value) // 1

Но ссылки разворачиваются при использовании в шаблоне, и .value не требуется.

<script setup>
import { ref } from 'vue'

const count = ref(0)

function increment() {
  count.value++
}
</script>

<template>
  <button @click="increment">
    {{ count }} // .value не нужен
  </button>
</template>

Но стоит быть внимательным: развертка работает только со свойствами верхнего уровня. Следующий фрагмент создаст [object Object]

// Так делать не надо
<script setup>
import { ref } from 'vue'

const object = { foo: ref(1) }

</script>

<template>
  {{ object.foo + 1 }}  // [object Object]
</template>

Правильное использование .value требует времени и вначале вы можете использовать его чаще, чем нужно.

4. Генерируемые (emmited) события

Начиная с релиза первой версии Vue, дочерний компонент может взаимодействовать с родительским с помощью генерируемых событий. Вам нужно было только добавить пользовательский слушатель для прослушивания события.

this.$emit('my-event')
<my-component @my-event="doSomething" />

Теперь генерируемые события должны быть объявлены с помощью макроса defineEmits.

<script setup>
const emit = defineEmits(['my-event'])
emit('my-event')
</script>

Еще одна вещь, о которой следует помнить, это то, что ни defineEmits, ни defineProps (используемые для объявления свойств) не нужно импортировать. Они автоматически доступны при setup script.

<script setup>
const props = defineProps({
  foo: String
})

const emit = defineEmits(['change', 'delete'])
// setup code
</script>

В итоге, поскольку события теперь должны быть объявлены, использование модификатора .native не требуется, и он фактически был удален.

5. Декларирование дополнительных опций

Есть несколько свойств метода Options API, которые не поддерживаются в script setup

  1. name
  2. inheritAttrs
  3. Пользовательские параметры, необходимые для плагинов или библиотек

Решение состоит в том, чтобы иметь 2 разных скрипта в одном компоненте, как определено в script setup RFC.

<script>
  export default {
    name: 'CustomName',
    inheritAttrs: false,
    customOptions: {}
  }
</script>

<script setup>
  // script setup logic
</script>

подробнее про сам script setup

6. Использование Reactivity Transform

Reactivity Transform было одной из экспериментальных, но противоречивых функций Vue 3, целью которой было упростить способ объявления компонента.

Идея заключалась в том, чтобы использовать преобразования времени компиляции, чтобы автоматически разворачивать ссылку и делать .value устаревшим. Но теперь он удален и будет удален в Vue 3.3. Он по-прежнему будет доступен в виде пакета, но, поскольку он не является частью ядра Vue, лучше не тратить на него время.

7. Определение асинхронных компонентов

Ранее асинхронные компоненты объявлялись путем включения их в функцию.

const asyncModal = () => import('./Modal.vue')

Начиная с Vue 3, асинхронные компоненты должны быть явно определены с помощью defineAsyncComponent.

import { defineAsyncComponent } from 'vue'

const asyncModal = defineAsyncComponent(() => import('./Modal.vue'))

8.Использование ненужных оберток в шаблонах

В Vue 2 требовался один корневой элемент для шаблона компонента, что иногда приводило к появлению ненужных оберток.

<!-- Layout.vue -->
<template>
  <div>
    <header>...</header>
    <main>...</main>
    <footer>...</footer>
  </div>
</template>

Это больше не так, поскольку теперь поддерживаются несколько корневых элементов.🥳

<!-- Layout.vue -->
<template>
  <header>...</header>
  <main v-bind="$attrs">...</main>
  <footer>...</footer>
</template>

9. Использование неправильных событий жизненного цикла

Все события жизненного цикла компонентов были переименованы либо путем добавления префикса on, либо путем полного изменения имени. Вы можете проверить все изменения на следующем рисунке.

10. Игнорирование чтения документации

Официальная документация была обновлена, чтобы отразить новые API и включить множество ценных заметок, руководств и рекомендаций. Даже если вы опытный инженер Vue 2, вы обязательно узнаете что-то новое, прочитав ее.

Заключение

У каждого фреймворка есть кривая обучения(когда надо научиться многому за короткий период времени), и Vue 3, несомненно, круче, чем Vue 2. Я все еще не уверен, что усилия по миграции между версиями оправданы, но composition API намного чище и кажется удобнее и логичнее после того, как вы освоите его.

Запомните:

Делать ошибки намного лучше, чем ничего не делать.

Оригинал статьи на английском https://fadamakis.com/10-mistakes-to-avoid-when-starting-with-vue-3-1d1ced8552ae


Последняя редакция 14 февраля, 2023 в 05:02