Создатель Solid.js Ryan Carniato год назад написал статью об эволюции Signals в JavaScript (чья концепция лежит и в основе реактивности Vue.js)
#reactivity #solidjs
#reactivity #solidjs
DEV Community
The Evolution of Signals in JavaScript
There has been some buzz recently in the frontend world around the term "Signals". In seemingly short...
Попались на глаза как-то исходники одного расширения к
Автор использует
Еще один пример использования
Вообще,
#reactivity
VS Code
.Автор использует
reactive, ref и watch
из Vue
, чтобы организовать в нём реактивность. UI
части нет.Еще один пример использования
Vue
реактивности в Node.js приложении.Вообще,
Reactivity API
как библиотека для удобного определения асинхронных связей между несколькими обычными переменными, обладает самостоятельным функционалом и может использоваться вне Vue.js
фреймворка и фронтенда в целом.#reactivity
GitHub
vscode-deepl/src/state.ts at main · soerenuhrbach/vscode-deepl
DeepL for Visual Studio Code. Contribute to soerenuhrbach/vscode-deepl development by creating an account on GitHub.
👍4
Во
Но:
1. Это не композабл по определению
2. Там не обязательно рефы
3. Они не "глобальны"
В общем случае структура данного объекта - экспортируемые из ES модуля реактивные данные и функции для работы с ними.
Функционально они заменяют "сторы"
Мне кажется, самое подходящее название для данной конструкции - [реактивный] бизнес объект (РБО). В них инкапсулируется логика предметной области и приложения, они не привязаны к конкретным компонентам, и по аналогии с другими языками и фреймворками, этот паттерн -
Кроме того, позиционирование именно как "бизнес объект" будет требовать явного отделения от него инфраструктурного слоя - работы с Backend API, например. То есть, стимулировать использование лучших практик и наработок из других сфер разработки ПО, еще более переводя
#architecture #vuejs #reactivity #rbo #composables
Vue 3
есть важная и нередко используемая конструкция, у которой нет имени. Это то, что обычно называют "композабл с глобальными рефами". Но:
1. Это не композабл по определению
2. Там не обязательно рефы
3. Они не "глобальны"
В общем случае структура данного объекта - экспортируемые из ES модуля реактивные данные и функции для работы с ними.
Функционально они заменяют "сторы"
Pinia
. Называть их тоже stores
двусмысленно и нелогично. Вообще, молиться на "глобальный стейт" после появления идеи JavaScript signals и их всевозможных реализаций, включая Vue Reactivity API
, архаично.Мне кажется, самое подходящее название для данной конструкции - [реактивный] бизнес объект (РБО). В них инкапсулируется логика предметной области и приложения, они не привязаны к конкретным компонентам, и по аналогии с другими языками и фреймворками, этот паттерн -
Business Object
- выглядит вполне подходящим.Кроме того, позиционирование именно как "бизнес объект" будет требовать явного отделения от него инфраструктурного слоя - работы с Backend API, например. То есть, стимулировать использование лучших практик и наработок из других сфер разработки ПО, еще более переводя
Vue.js
из фреймворка для небольших проектов в разряд enterprise level решений.#architecture #vuejs #reactivity #rbo #composables
👍7
Мы уже писали пару раз о применении
Вот новая библиотека/starter-kit, которая использует
Пока что
#vscode #reactivity
Reactivity API
пакета вне Vue
фронтенд приложений.Вот новая библиотека/starter-kit, которая использует
Vue Reactivity API
для упрощения создания VS Code
расширений. Путем отображения VSCode extension API
(которая основана на event driven архитектуре) в композаблы. Несколько понижается производительность, значительно повышается DX.Пока что
Vue Reactivity API
выглядит лучшей "реализацией" JS Signals
.#vscode #reactivity
kermanx.github.io
Reactive VSCode
Develop VSCode extension with Vue Reactivity API
🔥6
Я уже писал, как в 30 строк сделать глобальный прелоадер
В компонентах он включается/выключается так:
Всё работало прекрасно. Тут понадобилось кэшировать приходящие данные. Верней, приходили они партиями, и при выборе одного элемента через
После этого пришла мысль - а где должны быть
Правильно ли это? По-моему, да. Компонент отвечает только за свой контент. Загрузка данных, откуда она происходит, работа с прелоадером - это его не должно касаться.
Мощь
#reactivity
AppLoader
на всё приложение.В компонентах он включается/выключается так:
const { startLoading, stopLoading } = useAppLoader();
onMounted(async () => {
startLoading();
xr.value = await loadXr(props.vid);
stopLoading();
});
Всё работало прекрасно. Тут понадобилось кэшировать приходящие данные. Верней, приходили они партиями, и при выборе одного элемента через
props.vid
он мог как оказаться уже в кэше, так и его нужно было грузить по сети. Для этого была сделана промежуточная утилита (js
модуль), которая экспортировала асинхронный метод loadXr()
.После этого пришла мысль - а где должны быть
startLoading() / stopLoading()
для глобального прелоадера? Зачем им срабатывать, когда данные берутся из кэша? Перенес их в ту самую утилиту. В итоге компонент стал выглядеть так:onMounted(async () => {
xr.value = await loadXr(props.vid);
});
// или в корне setup-a:
loadXr(props.vid).then((data) => {
xr.value = data;
})
Правильно ли это? По-моему, да. Компонент отвечает только за свой контент. Загрузка данных, откуда она происходит, работа с прелоадером - это его не должно касаться.
<Suspense>
, который уже много лет пытаются внедрить во Vue
, выглядит совсем не как решение для серьезных приложений, где нужно явно контролировать потоки данных, а, скорей, уровня Nuxt
.Мощь
Vue Reactivity API
сильно недооценена, - в том числе, в официальной документации. Не надо бояться ее использовать.#reactivity
Telegram
Vue-FAQ
Глобальный прелоадер
Альтернативу много лет создающемуся Suspense несложно сделать самому с помощью одной composable функции в 30 строк.
Он нужен когда в нескольких компонентах могут асинхронно грузится данные, и нужно показывать один общий прелоадер пока…
Альтернативу много лет создающемуся Suspense несложно сделать самому с помощью одной composable функции в 30 строк.
Он нужен когда в нескольких компонентах могут асинхронно грузится данные, и нужно показывать один общий прелоадер пока…
👍6
Во
Реактивность будет не глубокой (
Так можно написать чуть более эффективный и минималистичный код, но использование этого не выглядит хорошей практикой.
Перед заменой функции происходит изменение некоего состояния компонента/приложения. Вот на него лучше и ориентироваться.
#reactivity
Vue
реактивными могут быть не только обычные переменные, но также ссылка на функцию, что вполне в духе JS
:<script setup>
import { computed, ref } from 'vue'
const f = ref(() => "Hello");
const v = computed(() => {
return f.value();
});
setTimeout(() => {
f.value = () => "World";
}, 3000 );
</script>
<template>
<h1>{{ v }}</h1>
</template>
Реактивность будет не глубокой (
shallow
)Так можно написать чуть более эффективный и минималистичный код, но использование этого не выглядит хорошей практикой.
Перед заменой функции происходит изменение некоего состояния компонента/приложения. Вот на него лучше и ориентироваться.
#reactivity
👍1
Чтобы выделить из компонента отдельно некий функционал с реактивным состоянием, были созданы
Чтобы использовать функционал с реактивным состоянием между несколькими компонентами, можно задействовать js модули либо
Иногда нужно нечто среднее - подобную сущность с реактивным стейтом и функционалом на нем, но используемую в нескольких связанных компонентах (например, в
В этом случае данный реактивный объект будет жить в своем ограниченном контексте и не будет конфликтовать с оставшейся частью проекта.
#reactivity #bestpractices #architecture
composable
функции (называемые "функциями", хотя по сути это объект созданный через js замыкание - closure).Чтобы использовать функционал с реактивным состоянием между несколькими компонентами, можно задействовать js модули либо
Pinia
/Vuex
сторы.Иногда нужно нечто среднее - подобную сущность с реактивным стейтом и функционалом на нем, но используемую в нескольких связанных компонентах (например, в
Tabs
или каких-то виджетах), - то есть, в некотором локальном контексте. Для этого можно в общем родительском компоненте создать composable
, который передать потомкам - либо через provide/inject
(лучше), либо через props
(не надо).В этом случае данный реактивный объект будет жить в своем ограниченном контексте и не будет конфликтовать с оставшейся частью проекта.
#reactivity #bestpractices #architecture
Telegram
Vue-FAQ
Во Vue 3 есть важная и нередко используемая конструкция, у которой нет имени. Это то, что обычно называют "композабл с глобальными рефами".
Но:
1. Это не композабл по определению
2. Там не обязательно рефы
3. Они не "глобальны"
В общем случае структура…
Но:
1. Это не композабл по определению
2. Там не обязательно рефы
3. Они не "глобальны"
В общем случае структура…
👍5🔥5🤔2❤1
Во
Основной плюс - возможность указывать дефолтные значения более человеческим способом:
Как это делалось ранее (и можно делать сейчас):
Деструктуризация пропсов - это осколки невзлетевшего
По сути деструктуризация пропсов это просто макрос, скрывающий под собой обычную работу с пропсами:
Минусы:
- Деструктурированные пропсы могут быть случайно переданы в функцию, что приведет к потере реактивности
- Пропсы перестают быть явными (становятся неотличимы от обычных переменных)
- Путаница для новичков с магией компилятора
Решение:
Не забывать работать с ними как с
#props #reactivity
Vue 3
вышла Reactive Props Destructure
- деструктуризация пропсовОсновной плюс - возможность указывать дефолтные значения более человеческим способом:
const { count = 0, msg = "hello" } = defineProps<{
count?: number;
message?: string;
}>();
const double = computed(() => count * 2);
Как это делалось ранее (и можно делать сейчас):
const props = withDefaults(
defineProps<{
count?: number;
msg?: string;
}>(),
{
count: 0,
msg: "hello",
}
);
Деструктуризация пропсов - это осколки невзлетевшего
Reactivity Transform
По сути деструктуризация пропсов это просто макрос, скрывающий под собой обычную работу с пропсами:
// на входе
const { count } = defineProps(["count"]);
console.log(count);
// на выходе компилятора
const __props = defineProps(["count"]);
console.log(__props.count);
Минусы:
- Деструктурированные пропсы могут быть случайно переданы в функцию, что приведет к потере реактивности
- Пропсы перестают быть явными (становятся неотличимы от обычных переменных)
- Путаница для новичков с магией компилятора
Решение:
Не забывать работать с ними как с
props.X
либо не использовать деструктуризацию.#props #reactivity
👍15👎1
Поговорим о Shared composables
Страшный термин, который многие понимают, как хотят.
Во
1. Composable
Это технически (
2. "Модульный реф" / Pinia store
Тоже можно считать объектом в смысле
3. Shared composable как в примерах в документации во VueUse и Vue
Рождается как
Некоторые разработчики (не будем показывать пальцем) уверены, что использование
Не обладая знаниями Мурыча, тем не менее давайте намного порассуждаем.
Вот у нас есть модульный реф с рефом. Вот он используется, потом все компоненты со ссылкой на него, уничтожаются. Что происходит? Ничего. У него нет внешних зависимостей, он просто лежит мертвым грузом в памяти, занимая свои несчастные пару килобайт. Появился использующий его компонент - он заработал.
Как с
Так для чего нужен shared composable?
Посмотрим на примеры в документациях. Мы создаем реф с отслеживанием движения мышки. А вот это уже важно - если мы в каждом требующем координаты мышки компоненте будем создавать
Таким образом,
состояние в shared composable выполняет не самостоятельную функцию, а является просто адаптером для некого внешнего сервиса / Web API.
И суть
Даже чисто логически если подумать (по описанному выше юз-кейсу в пункте 3), то
Но, опять же, если подумать, то данная логика (оптимизация работы с внешним сервисом) очень похожа на логику работы глобального лоадера. И реализована может быть так же в несколько строк, безо всяких
#composable #reactivity
Страшный термин, который многие понимают, как хотят.
Во
Vue 3
у компонента есть, по большому счету, три варианта работы с внешними реактивными данными1. Composable
Это технически (
JS closure
) и по факту (ООП
) объект с данными и поведением. Компонент его создает, пользуется, при уничтожении компонента обнуляется ссылка на объект, и он подлежит уборке Garbage Collector
-ом (GC
).2. "Модульный реф" / Pinia store
Тоже можно считать объектом в смысле
ООП
, но реализующим паттерн Singleton
. Создается при первом вызове его кем-либо, затем ссылка на него записывается в некий глобальный реестр, и любой другой компонент, обращающийся к этой структуре, получает эту ссылку и работает с тем же самым инстансом.3. Shared composable как в примерах в документации во VueUse и Vue
Рождается как
стор
, умирает как обычный composable
. При первом обращении создается один объект, который затем используется всеми компонентами, которым он нужен. Но как только не остается ни одного такого компонента, этот объект "умирает". В дальнейшем если он понадобится, он создается опять в одном экземпляре.Некоторые разработчики (не будем показывать пальцем) уверены, что использование
shared composable
именно как реактивного стейта вместо модульного рефа/стора помогает сделать программу эффективней.Не обладая знаниями Мурыча, тем не менее давайте намного порассуждаем.
Вот у нас есть модульный реф с рефом. Вот он используется, потом все компоненты со ссылкой на него, уничтожаются. Что происходит? Ничего. У него нет внешних зависимостей, он просто лежит мертвым грузом в памяти, занимая свои несчастные пару килобайт. Появился использующий его компонент - он заработал.
Как с
shared composable
? Вот он создается, используется, потом все компоненты, его использующие, кончаются - и он должен типа уничтожиться. Вызывается код по обнулению, но у Garbage Collector
-а JS 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
👍14👎7
Мэйнтенер
Уверяют, что она самая быстрая, и пытаются встроить ее везде где могут - в системы стейт менеджмента для
Пока наталкиваются на "непонимание".
Также хотят встроить ее во
Но по поводу увеличения скорости на проценты хотелось бы спросить Эвана - зачем же он тогда перешел на
#vuejs #performance #reactivity
Volar
Джонсон со своим помощником последние недели носятся с alien-signals
- своей реализацией Signals
в JSУверяют, что она самая быстрая, и пытаются встроить ее везде где могут - в системы стейт менеджмента для
Solid.js
, Dart
, Lua
. Движение unjs
выходит за рамки js
.Пока наталкиваются на "непонимание".
Также хотят встроить ее во
Vue
. Эван, вроде, одобряет.Но по поводу увеличения скорости на проценты хотелось бы спросить Эвана - зачем же он тогда перешел на
js
Proxy
в своей системе реактивности и ухудшил производительность в десятки и сотни раз, если скорость так важна?#vuejs #performance #reactivity
🤡5💩4🥴3
// useUserService.ts
function isAuthenticated() {
return !!user.value;
}
// Component A
<script>
const { isAuthenticated } = useUserService();
</script>
<template>
<p v-if="isAuthenticated()">hello</p>
</template>
Функции во
Vue
ведут себя не совсем как функцииВ данном примере функция
isAuthenticated()
ведет себя как computed
и будет вызываться каждый раз, когда user
изменится или компонент А
будет перерисовываться.Происходит это из-за того, что
Vue
определяет все реактивные зависимости внутри тела функции и перерендивает компонент, когда кто-то из них меняется.Таким образом, большой разницы в использовании функции вместо
computed
нет. Но если внутри большая логика, то лучше использовать computed
, потому что он будет пересчитываться только когда его зависимости изменились, а функция - при любом рендеринге#reactivity #tip #optimization
❤10💩3👍2😁2👎1🌚1