Vue-FAQ
924 subscribers
562 photos
90 videos
557 links
Канал сайта https://vue-faq.org
Информация о Vue.js, фронтенд разработке и не только

Contacts: @RuslanMakarov
Download Telegram
Поговорим о Shared composables

Страшный термин, который многие понимают, как хотят.

Во Vue 3 у компонента есть, по большому счету, три варианта работы с внешними реактивными данными

1. Composable

Это технически (JS closure) и по факту (ООП) объект с данными и поведением. Компонент его создает, пользуется, при уничтожении компонента обнуляется ссылка на объект, и он подлежит уборке Garbage Collector-ом (GC).

2. "Модульный реф" / Pinia store

Тоже можно считать объектом в смысле ООП, но реализующим паттерн Singleton. Создается при первом вызове его кем-либо, затем ссылка на него записывается в некий глобальный реестр, и любой другой компонент, обращающийся к этой структуре, получает эту ссылку и работает с тем же самым инстансом.

3. Shared composable как в примерах в документации во VueUse и Vue

Рождается как стор, умирает как обычный composable. При первом обращении создается один объект, который затем используется всеми компонентами, которым он нужен. Но как только не остается ни одного такого компонента, этот объект "умирает". В дальнейшем если он понадобится, он создается опять в одном экземпляре.

Некоторые разработчики (не будем показывать пальцем) уверены, что использование shared composable именно как реактивного стейта вместо модульного рефа/стора помогает сделать программу эффективней.

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

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

Как с shared composable? Вот он создается, используется, потом все компоненты, его использующие, кончаются - и он должен типа уничтожиться. Вызывается код по обнулению, но у Garbage CollectorJS VM своя логика работы, и он не будет чистить эту память сразу. А если и будет - потратит на это ресурсы CPU. Затем снова появляется компонент, которому нужен этот объект - и он снова создается, тратятся ресурсы CPU, выделяется новая память. И так по кругу. В итоге, через 10 циклов у нас в куче памяти в 10 раз больше, чем нам надо, зарезервированного места, и мы потратили в десять раз больше ресурсов на создание/уничтожение структуры.

Так для чего нужен shared composable?

Посмотрим на примеры в документациях. Мы создаем реф с отслеживанием движения мышки. А вот это уже важно - если мы в каждом требующем координаты мышки компоненте будем создавать composable с этой логикой, мы будем множить слушателей этого события, и это дорогая операция. Держать слушателя постоянно в глобальном сторе - тоже ненужная трата ресурсов.

Таким образом,

состояние в shared composable выполняет не самостоятельную функцию, а является просто адаптером для некого внешнего сервиса / Web API.

И суть shared composable - создать единую реактивную точку доступа к внешнему сервису.

Даже чисто логически если подумать (по описанному выше юз-кейсу в пункте 3), то shared composable не может использоваться для непосредственного обмена данными между компонентами. Он может только передавать данные во внешний сервис, и получать их оттуда. Даже vueuse/useLocalStorage так работает. И если передача не удалась - это ошибка выполнения программы.

Но, опять же, если подумать, то данная логика (оптимизация работы с внешним сервисом) очень похожа на логику работы глобального лоадера. И реализована может быть так же в несколько строк, безо всяких effectScope и прочих заморочек - простым и понятным кодом. Нету там ничего из Composition API, что надобилось бы для реализации данной логики. Обычный модульный реф и синхронный код для отслеживания числа подписчиков с подключением/отключением этого рефа к внешнему сервису.

Ref, reactive, shallowRef, watch и computed должны покрывать 99.9% потребностей прикладного программирования на Vue.js. Не надо делать простое сложным.

Shared composable как он есть - изначально неудачное название и ненужная структура. Предлагается не использовать.

#composable #reactivity