Vue-костыли и странности: от классики до дичи (часть 1)

1. Иллюзия уникальности: префиксы к индексам в «v-for»

Как часто встречается: Почти в каждом проекте, где линтер заставил поставить ключ.

Схема: «<div v-for=“(item, idx) in list” :key=“`super-unique-key-${idx}`”>» Для Vue префикс «super-unique-key-» не имеет никакого значения, в ключе остаются теже индексы.

В чем боль: Разработчик верит, что строковый префикс делает ключ уникальным. На самом деле для Vue это абсолютно тот же самый индекс массива (idx). Пример на пальцах, допустим наши элементы привязаны к индексам: item1 - key=index-0 item2 - key=index-1 - // удаляем item2 item3 - key=index-2

item1 - key=index-0 item3 - key=index-1 - // индекс сдвинулся, ключ изменился!

Vue запутается, анимации сломаются, а неконтролируемые инпуты сохранят старые значения. Префикс просто глушит линтер, но не решает проблему.

Когда споткнемся: Когда получим динамично меняющийся список: элементы удаляются, переставляются и всякое в таком духе.

Как надо: Использовать реально уникальный ID (:key=“item.id”). Если его нет - генерировать UUID до начала отрисовки списка. Сначала формируем список с уникальными ключами, только потом этот список выводим в v-for.

2. Шаблон-Франкенштейн: JS-простыня внутри HTML

Как часто встречается: Постоянно, когда лень выносить логику в скрипт ради «одного простого условия».

Схема: <div>{{ items.filter(i => i.active && i.price > 100).map(i => i.name.toUpperCase()).join(', ') || ‘Пусто’ }}</div>

В чем боль: - Логика не кэшируется при перерендере. В отличие от computed, у выражений внутри {{ }} нет умного кэша. Если в компоненте изменится любая другая реактивная переменная (например, открылся модальный контент или обновился счетчик), компонент запустит перерендер. И Vue будет вынужден заново прогонять тяжелые filter и map по массиву, даже если сам массив не менялся.

- Ад при дебаге. Если в данных прилетит undefined или null, страница упадет с «белым экраном», а стек-трейс в консоли укажет на анонимную функцию внутри огромной скомпилированной рендер-функции. Удачи в поисках того, какой именно баг всё сломал.

- Нулевое переиспользование. Если вам понадобится точно такое же отформатированное значение в другом конце этого же компонента (или в дочернем), вам придется скопировать всю эту JS-простыню.

Как надо: Держать шаблон «глупым». Всю тяжелую артиллерию с методами массивов выносить строго в computed.

// script const activeItemsNames = computed(() => items     .filter(i => i.active && i.price > 100)     .map(i => i.name.toUpperCase())     .join(', ') || ‘Пусто’ ) // template <div>{{ activeItemsNames }}</div> // чистый шаблон

Когда споткнемся: Когда компонент начнет разрастаться, обрастать другими реактивными стейтами, а массивы внутри инлайн-выражений увеличатся до сотен элементов, создавая микрофризы на ровном месте.

А у вас есть "любимый" хак в Vue? Делитесь в комментариях!