Что такое ViewModel во Vue и как он работает
Что проверяют
Знаете ли вы, из чего состоит связка данных и шаблона во Vue, или выучили только слово MVVM. По ответу видно, писали ли вы на Vue сами: тот, кто писал, сразу говорит про реактивность и про места, где она протекает.
Как отвечать
ViewModel это экземпляр приложения или компонента, который держит состояние и связывает его с разметкой. Модель это данные, представление это шаблон, ViewModel это прослойка между ними, и в коде её по традиции называют vm.
Что внутри:
- реактивность: Vue оборачивает состояние, чтобы знать, кто его читает. Во второй версии это делалось через
Object.defineProperty, в третьей черезProxy, поэтому третья видит и добавление новых ключей, и запись по индексу массива; - отслеживание зависимостей: при рендере компонент запоминает, какие поля прочитал. Поле изменилось, перерисовался только тот компонент, который его читал, а не всё дерево;
- связывание:
v-bindотдаёт значение в разметку,v-modelделает двустороннюю связь и разворачивается в привязку значения плюс обработчик события; - вычисляемые свойства:
computedкэшируется по зависимостям и пересчитывается только при их изменении, метод вызывается на каждый рендер; - жизненный цикл: хуки монтирования и размонтирования это точки, где появляется доступ к DOM и убираются подписки.
Стоит добавить, что в Composition API отдельного объекта ViewModel как такового нет: состояние собирается в setup через ref и reactive, но роль прослойки остаётся той же.
Где спотыкаются
Говорят, что Vue сам следит за любыми изменениями, и не знают ограничений. Во второй версии добавленное после создания поле реактивным не становилось, и нужен был отдельный вызов установки свойства. На проектах, которые не переехали, это до сих пор всплывает.
Второе: теряют реактивность при деструктуризации. Вытащили поле из реактивного объекта в обычную переменную, и связь с шаблоном пропала. Лечится toRefs или работой через ref с обращением к .value.
Третье: путают ViewModel с хранилищем и тащат в компонент состояние всего приложения. Рядом стоит вторая ошибка: изменяют props напрямую. Поток данных идёт сверху вниз, наверх уходит событие.