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
name
inheritAttrs
- Пользовательские параметры, необходимые для плагинов или библиотек
Решение состоит в том, чтобы иметь 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