Pull to refresh

Comments 94

у меня в последнем cli написано preview
Речь про vue или про vue-cli? Сам vue релизнулся, всякие vue-cli и прочие вещи с v3.vuejs.org/guide/migration/introduction.html#supporting-libraries по большей части отмечены как пререлизы. Об этом в статье написано.
UPD: проверил. При создании из vue-cli действительно так.
Я не могу найти ссылку на оригинальную статью. Ссылка в заголовке ведет на гитхаб
UFO just landed and posted this here

Ага особенно весело разработчикам всяких плагинов и ui библиотек. Наша песня хороша, начинай сначала

Ну все таки это не так больно, как с python. А новые апи действительно дают много хороших возможностей (хотя может быть даже слишком много :))
Было бы здорово, если бы кто-то сделал скрипт, который конвертирует vue2->vue3 :)
Ну либо доходчиво расписал, что менять надо.
Поддержка тайпскрипта условная к сожалению, потому что в шаблонах тайпчекинга нет, чисто в IDE подсказки есть с автокомплитом, но если поменялся интерфейс и в шаблонах использованы не актуальные имена полей, то вам об этом никто не скажет. Все молча соберется без ошибок.
Пробовали vetur.validation.props установить в true?
Причем тут настройка плагина для IDE и сборка проекта, которая не падает при нарушении типизации?
Понял, о чем речь. В качестве обходного решения можно добавить vti в конвейер сборки, он будет ругаться на неправильные/отсутствующие props.
WIP. This feature is not stable yet.
Плюс это костыль и хотелось бы это из коробки, раз речь идет о поддержке Typescript'a.
Ну да, костыль. просто я его себе с пол года назад настроил и забыл :)
как именно в режиме разработки?
Так во время сборщика при разработки их тоже видить надо где поломались файлы, а не только во время коммита или когда файлы открыт в IDE
Ну добавьте в скрипт сборки эту команду в конвейер непосредственно перед командой сборки. Например
vti diagnostics && vue-cli-service build

Единственное, что будет не совсем правильно работать — hot reload. Но терпимо.
Ну в целом сойдет, но конечно если бы тайпчекинг работал из коробки было бы круто
Зачем они поддержку IE11 тащат? Кому IE нужен может на второй ветке остаться. Так где нужна поддержка IE11 вряд ли озабочены актуальностью версий фреймворков.
Ну вот, например, мне нужна поддержка IE11. И, как минимум, достаточно немалое увеличение производительности 3-й версии тоже хотелось бы. Да и под вопросом стоит, а будет ли кто-то еще разрабатывать под вторую версию (ui-либы там и т.д.)
Я не знаю где вам IE11 понадобился, сейчас куча людей на FireFox уже забивает, хотя его поддержку обеспечить не так сложно.

Сколько пользователей у вас на IE11 в %?
Пока vuetify не перешли, тоже не будут. Рано пока.
UFO just landed and posted this here
А потом «почему все смеются над JS-экосистемой». Да потому что в прошлом году начали крупный проект на актуальном, модном, и современном VueJS, а уже через полтора года окажется что у нас фронт построен на устаревшем фреймворке у которого вот-вот закончится поддержка. Меньше трёх лет, с состояния «на самых новых технологиях» в состояние «жуткое легаси». И как вот с этим жить вообще? Надеюсь сообщество форкнет последнюю версию 2.х, и будет развивать её параллельно.

Просто JS развивается очень быстро и стремительно, и дело не в Vue.js, Angular, React и т.п. Просто сам по себе код который ты писал 2 года назад, он хочешь того или нет превращается в легаси. Как минимум по тому, что ты сам становишься умнее и растешь.
Меняешь работу, уходишь на новый проект с чистого листа и ты всегда на гребне волны. Ибо чахнуть в легаси коде такое себе удовольствие и перспектива, хотя для кого то это норма и в порядке вещей, но тут уже сколько людей столько и мнений.
Из часто используемого там — неглобальный инстанс vue, вынесенные за скобки инстанса $nextTick и подобные, самое сложное — дефолтные значения props не имеют доступа к this и v-model поменялся (зато теперь несколько переменных можно связывать независимо с меньшим количеством букв и появился доступ к модификаторам, например v-model.number). Ну и фильтры выпилены. В общем, почитав соответствующий раздел сделал вывод, что если тесты есть, то можно перейти за несколько дней на новую версию даже на крупных проектах. Я на паре своих внутренних проектов попробовал в отдельной ветке — заняло пару часов.
Если у вас в проекте больше своей логики, и нет острой зависимости от сторонних плагинов, ничего страшного нет, если вы перейдете на новую версию когда будет удобно Вам. JS очень гибкий, и зачастую нет нужды кидаться и переписывать все полностью. У нас стратегия мягкого перехода, мигрируем постепенно модуль за модулем, когда на это есть ресурсы.

Это отличная новость. Так как Vue больше подходит для новичков, теперь приложения написанные с его помощью, приблизятся по возможностям к таким конкурентам как React и Angular.

UFO just landed and posted this here
А вот примера, что можно на React или Angular и нельзя на Vue, почему-то не приводят.

  • Фрагменты до Vue3, ЕМНИП, нельзя было использовать.
  • Ну и observable модель лежащая в основе Vue на любителя. Они зачем-то реализовали зависимость одного computed значения от другого путём полной переподписки на все зависимости второго (О_о). Наверное так проще, но как блин с этим жить, в случае когда модель данных большая и тесно переплетённая? Возможно во Vue3 это поправили, не знаю. Не следил
  • Поддержка TS в шаблонах, судя даже по этой статье, пока в зачаточном состоянии.
  • Если не исповедовать принцип 3в1 (стили + код + шаблон в одном файле), то возникали бубны с прекомпиляцией шаблонов. Там были сложности. Я создавал issue, и получил от команды разработчиков ответ, что всё что не 3в1 это не канон, так что шёл бы я лесом. Ну такое. А писать множество крошечных компонент в рамках одного файла в 3в1, кажется, нельзя. Для меня это уже сильный аргумент против. Сильно мешает декомпозиции, которую я очень люблю. В React такой проблемы нет от слова совсем.

Знай я Vue побольше, мог бы сравнить плотнее. Из того что понравилось — очень вкусный шаблонизатор. JSX со своими &&, ?:, .map((item, idx) => ()) и рядом не стоял. Много синтаксического сахара в виде таких штук как .prevent, .keyDown.enter, .passive и пр. (за точность не ручаюсь, пишу по памяти). Нативная поддержка слотов.


P.S. Я не Vue-hater, но захоти я писать с observable, я бы, наверное, попробовал бы React + MobX, или React + RxJS. Vue сильно ужалил своим watcher.demand и переподпиской. И отсутствием фрагментов (были только криво работающие костыли) тоже. Однако очень приятно наблюдать, что он быстро развивается. Этакий KnockoutJS с человеческим лицом (и ужасной моделью observable)

Все нормально с реактивностью во vue сейчас, особенно в версии 3. Тем более никто и ничто не мешает использовать Vue в паре с MobX, я пробовал, они отлично дружат.
ничто не мешает использовать Vue в паре с MobX

Охотно верю. Но зачем?! Звучит как безумие. Особенно учитывая что во Vue3 всё торчит наружу.

На случай если реактивность vue не устраивает) Меня то устраивает) Просто говорю что есть такая возможность в случае чего
UFO just landed and posted this here
Мне кажется, что вы переносите практики Реакта или Ангуляра на Vue, и получаются сложности

Честно говоря, я не горю желанием вдаваться в объяснения:


  • почему типизация это хорошо и какие проблемы она решает
  • почему O(n) вместо O(1) это плохо, и в каких контекстах это катастрофа
  • почему возможность возврата не-единичной ноды сильно упрощает некоторые сложные задачи

Т.к. писать про это придётся очень много. С примерами. А вы, наверное, продолжите спорить в текущем ключе (аля "не нужон мне ваш инторнет этот"). Вам не нужон. А мне очень нужен. Я пишу SPA уже много лет. От очень маленьких, до очень больших. И хорошо понимаю что мне нужно от инструмента. Когда инструмент заставляет меня приседать и вставляет мне палки в колёса — это выходит боком бизнесу. Все существующие на рынке инструменты заставляют это делать. Если вы считаете, что ваш инструмент не заставляет, то вы просто приседаете, думая, что не приседаете :-) Это скорее вопрос осведомлённости и опыта. Правда такова — все существующие фреймворки очень далеки от идеала. Чтобы фанбои об этом не думали. Разработка сложных продуктов сводится к умелому лавированию между костылями и дедлайнами.

UFO just landed and posted this here
Можно же и кратко описать суть

псевдокод:


a = computed(() => { /* touch 5000 observables */ });
b = computed(() => a() + 1);

Для вычисления b, при уже вычисленном a достаточно просто взять результат от a (который закеширован) и добавить к нему 1. KnockoutJS так бы и сделал. Помимо этого он бы автоматически подписал b на a. Таким образом при изменении значения в a, будут уведомлены все подписчики. Это пересчитает b. Vue2 (уточню — когда я его дебажил) делает не так. Он тоже берёт закешированное значение и добавляет 1. Но помимо прочего он подписывает b на все те 5000 observables, на которые был подписан a. Даже когда a уже вычислен. Т.е. просто сложить два числа — 5000 операций на подписку.


Затем мы берём наш b-computed и помещаем его результат в таблицу. Скажем 10 на 10. В каждую ячейку. В какой-нибудь v-bind. Все эти штуки тоже являются computed значениями. Что они делают? Ага… Копируют 5000 зависимостей. И так на каждом шаге везде по многу многу раз. Чем лучше декомпозиция, тем драматичнее эффект.


Как это обойти? Ну можно вместо computed на всех крупных узлах использовать watch. В моей задаче проще было выкинуть Vue, чем так уродоваться.


И кстати для Vue 2 плагин fragments давно есть.

Очень условно есть. По сути его нет. Он практически не функционирует. Во всяком случае, когда я его трогал, он падал даже на самых тривиальных кейсах. Возможно с тех пор что-нибудь изменилось, я не проверял.


Меня по первой выручил display: contents


выглядит голословно

Ок. Так и останется. Не буду ничего доказывать.


При прочих плюсах, этот недостаток не критичен.

Это шутка? Больше всего в случае React мне TS помогает как раз в props-ах. Это, имхо, самое главное.

UFO just landed and posted this here
ИМХО Если у вас computed зависит от больше чем трех переменных, то наверно лучше рефакторинг.

declare const students = observableArray();
_.times(5000, idx => students.push(genFakeStudent(idx));
const grownUpStudents = computed(() => students.filter(student => student.age >= 18));

Та дам. Ваш computed зависит от 1-й переменной. Ой. Нет. От пяти тысяч. Вот жеж засада. Надо декомпозировать его на 1333 разных computed-а.


Сложных задач видал много

не дебажил

;-) Никогда не понимал, как можно пользоваться своим главным инструментом, не понимая, как он работает. Когда я писал с jQuery, я целыми днями утопал в их исходном коде и писал свои плагины. Когда я работал с KnockoutJS я днями утопал в дебаге всех этих хитросплетённых observables (они там в разы сложнее, чем во Vue). Когда я писал на Vue я вынужденно отлавливал причину всех этих тормозов, разбирался в принципе работы шаблонизатора и его прекомпиляции. Когда я работал (и работаю с React) я дебажу работу Fibers и их очередь. Работая с Babel и Webpack я сталкиваюсь с необходимостью написания своих плагинов для них.


Какие такие сложные задачи вы решаете, которые не подразумевают дебаг и чтение сорцов? :-) Вот вы выше пишете:


А вот примера, что можно на React или Angular и нельзя на Vue, почему-то не приводят.

Я не уверен что вам вообще нужен ответ. Ведь "мне это не надо", "это не критично", "я бы зарефакторил", "я не сталкивался". Т.е. всё вам приводят, вам просто не интересно\не нужно.

UFO just landed and posted this here

А вы не подменяйте задачу :-)


Нужен именно полноценный observable-массив, в котором каждый элемент тоже реактивен. На отдельно взятые элементы (и даже их поля) будут подписаны уже другие компоненты ниже по древу.


И если мне не изменяет память, то Vue в вашем случае как раз в глубину результат выполнения .data() и обернёт. Т.е. будет отслеживать не изменение объекта в целом, а изменение:


  • объекта в целом
  • каждого студента в отдельности
  • поля age у каждого студента

Т.е. 5000 + 5000 + 1 зависимость. А теперь добавьте в табличку 10х10 в какой-нибудь v-bind этот computed, и смело умножайте те 10_001 на 100. В моём случае там речь шла у сотнях миллионах операций (все из которых лишние)


Впрочем за это ручаться не буду, т.к. ковырял Vue последний раз года два назад. ЕМНИП то для того чтобы Vue2 не оборачивал всё в глубину своими get-ами и set-ами нужно было какой-то отдельный сторонний эпичный костыль тащить в приложение.


// UPD1. на age зависимостей не будет, т.к. листья во Vue не реактивные сами по себе (как к примеру в knockout-е). Их реактивность обеспечивается get-ом объекта носителя. Так что не 5000 + 5000 + 1, а 5000 + 1


// UPD2. Да я правильно запомнил, Vue в глубину проходит. Так что реактивными являются все элементы массива. Они все "115: {ob: Observer}" вот такие обёртки с отслеживанием зависимостей

UFO just landed and posted this here
Во vue вы и не сможете отдельно каждый элемент сделать реактивным, так как уже сам массив реактивен. Другой подход.

Не сможете сделать НЕ реактивным. Vue всё оборачивает за вас. Ну ей богу. Уж если вы пишете на Vue, сделайте console.log и посмотрите во что ваши массивы превращаются:



то наверное речь уже не про data родительского компонента

Ниже в комментарии ссылка на песочницу. Минимально переделанный ваш же код. Тот самый .data(). Святая святых Vue компонент. Удивительно что я открываю вам Эврику )


Vuex использует те же observable под капотом. Они работают точно так же. Это они же (ЕМНИП). Во Vue3 они теперь доступны и простым смертным без всяких компонент.


Предлагаю вам на досуге всё таки подебажить Vue. Хотя бы пробежаться по вашим моделям и поизучать их под console.log. А можно и в код заглянуть, посмотреть как устроена реактивность под капотом :)

Поигрался в песочнице с вашим кодом. Ну собственно вроде бы ничего не поменялось.


  1. Да Vue сделал 5001 observable (а не 1)
  2. Да он сделал 5000 + 5000 + 1 + 1 подписку


Vue 2.6.11


А вот что происходит после добавления такого кода:


computed: {
  test() { ... },
  test2() {
      return this.test + 1;
  }


Заметьте уже по 3 подписки. Наш +1 как раз сюда и пролез. В каждый из observable.

UFO just landed and posted this here

Ну вот я открыл ссылку и снова получил то же самое:



Не знаю куда именно вы смотрите. Нужно чтобы проект запустился и test2 считался (т.е. компонент отрендерился, т.к. там всё "ленивое").


В целом sandbox этот кривоват (там какие-то мутки с iframe вроде бы), так что для чистоты эксперимента можете скачать себе весь проект целиком и подебажить уже локально.


Вот из Firefox. Впрочем было бы странно если бы это зависело от браузера

UFO just landed and posted this here
Но является ли это проблемой пока не разобрался

Зависит от проекта. У меня был проект — приложение для построения расписания занятий для школ. Решил на нём и поиграться в боевую с Vue2. 5000 observables это всевозможные необходимые данные об учителях, учениках, кабинетах, предметах и т.д… Всё то, что нужно для формирования расписания. Там очень непростая и теснопереплетённая область.


Приложение в реальном времени должно было просчитывать возможные варианты. Например надо разметить ещё 1 урок информатики. Завуч начинает drag-n-drop у уже сразу видит какие ячейки недоступны, а какие нежелательны, а какие рекомендованы. Это вовлекает в себя пересчёт кучу данных. Целое древо калькуляций. И любое звено может быть изменено в любой момент. Т.к. можно редактировать все эти данные не отходя от кассы. И да, расписание это таблица. А таблица это X-Y ячеек. Каждая из которых это с десяток computed-ов (просто так устроен Vue). И каждая будет заниматься копированием всех этих зависимостей на любой рендер (даже холостой повторный).


Это очень просто решается при помощи observable. Но как оказалось не во Vue :) В случае Vue это выливалось в то, что он считал всё что нужно, скажем, за 3мс, а перекладывал зависимости за 900мс. Или за 5секунд. Причём дело именно в конкретной реализации, которую взяли за основу во Vue.


Так что ответ на ваш вопрос — зависит от задач. Пока у вас небольшой граф данных, оно вполне себе будет ворочаться без особых тормозов. Потребуется тяжёлая артилеррия будете приседать или вообще подключать стороннее решение (например rxJs или mobX).


А что, такого поведения нету в Реакте и Ангуляре?

Я почти ничего не знаю про Angular. Но вот в KnockoutJS такого поведения нет. Там 5000 зависимостей будут только у А. А у Б будет всего 1. Нокаут вообще в разы сложнее устроен.


Касательно React — там нет observables. Там всё устроено совершенно иначе. Я решил ту же самую задачу на React за счёт селекторов и мемоизации. Что примечательно даже код особенно переписывать не пришлось. Просто вместо vuex.selectors & computed стали везде селекторы из reselect. Бизнес логика осталась неизменной. Чуть ли не автозаменой прошёлся.


Принцип работы всего этого под капотом совсем другой. Он не лучше и не хуже, чем observables, он другой. Так что да, такого поведения там не было.

UFO just landed and posted this here
Вообще я думаю логично оставить для Vue работу с интерфейсом, а логику калькуляций и т.д. поручить отдельному бизнес модулю или модулям

У меня так и было. Я взял Vuex. Я не писал эту логику в компонентах. Она была в отдельном слое.


Я мог бы взять какое-нибудь другое решение. Например RxJS или KnockoutJS. Или MobX. А потом изолентой скреплять этот модуль бизнес-логики с Vue (т.к. у Vue своя модель реактивности). Тогда бы оно заработало. Всё так. Один только вопрос остаётся — а на кой чёрт мне тогда Vue? Ну серьёзно. Если я беру Vue и игнорирую его реактивность, что в нём остаётся то? Шаблонизатор? Т.е. взять большой reactive framework с observable, взять стороннее observable решение для модели данных, скреплять их изолентой и выливать в продакшн? Увольте. Я просто выкинул Vue. И сейчас бы сделал точно так же. И впредь едва ли возьму Vue на серьёзные проекты, зная о таких вот приколах. Кто знает куда ещё они там воткнули O(n) шутки ради?


А вообще, я рекомендую вам воздержаться от подобных споров. Хотя бы до тех пор, пока вы свои инструменты не изучите. А то получается, что вы пытаетесь отстоять позиции Vue, которого сами не знаете. Умение писать v-bind= не эквивалентно знанию фреймворка. У нас с вами спор односторонний. Так не интересно.


Во время собеседования на Senior Frontend Developer мы обязательно спрашиваем кандидата вопросы про устройство его любимого framework-а. Будь это Vue, будь это Angular, React… Не важно. Хоть Svelte. Если человек не может внятно объяснить природу действия его главного инструмента, мы его не берём. В случае Vue мы спрашиваем как устроен паттерн observable, как работает авто-детектирование зависимостей. Если кандидат хорошо отвечает, спрашиваем какие оптимизации производительности он знает и применяет. Да, мы не делим людей на "создателей framework-ов" и "тех кто ими пользуется". Любой действительно опытный разработчик может подобный framework в упрощённом виде написать сам за неделю полторы. Если же человек пишет на ощупь, предполагая что там везде "магия"… Ну пусть пишет дальше. Но в другом месте.


Некоторые кандидаты "выпендриваются" и пишут техн. задание со своими observable "на коленке". Такое мы любим :)

UFO just landed and posted this here
Во время собеседования на Senior Frontend Developer мы обязательно спрашиваем кандидата вопросы про устройство его любимого framework-а

What the fuck?
А как устроена ваша любимая игрушка (ну шейдеры там) вы знаете?
У вас фронтенд синьёры выбирают фрейм для проекта?
Может стоит нанять project architect ?

Может стоит нанять project architect?

Было бы неплохо. Но к архитекту требования выше, чем к просто "синьёру".


What the fuck?

А зачем нанимать человека с амбициями "хочу много много денег", который без присмотра шагу сдвинуться не может?


На всякий случай уточню — вопросы поверхностного характера. Никто разумеется не спрашивает нюансы. Но если человек пишет на Vue и не может на коленке написать простой observable, не понимает как работает трекинг зависимостей… И при этом претендует на "хочу много много денег", то мы пожелаем ему удачи в другом месте.


Если человек пишет на React и не знает его основ (как работают props, context, зачем нужны key, что такое мемоизация и пр.), то ему будет ну прямо очень сложно у нас.


При этом сам фреймворк вторичен. Главное чтобы голова работала.


А как устроена ваша любимая игрушка (ну шейдеры там) вы знаете?

Не понял причём тут мы и игрушки. Но уверен, что нанимаясь на должность senior C++ game developer вы будете вынуждены отвечать на целый ворох вопросов из области 3D. В том числе и вопросы по шейдерам.

Но если человек пишет на Vue и не может на коленке написать простой observable, не понимает как работает трекинг зависимостей…

Ну в этом за день можно разобраться )
Если понадобится...


При этом сам фреймворк вторичен. Главное чтобы голова работала.

true, я думал вы просто "пшел нах" на ответ "если надо разберусь" говорите )


Не понял причём тут мы и игрушки.

Ну это такой "пирует" был, типа "фреймворк как игрушка" )

  1. Селекторы и мемоизация — это про работу с иммутабельным состоянием, так ведь? А разве в vue так нельзя сделать? Ну, то есть не полагаться на observableArray вообще, а всегда возращать новый инстанс массива, с новыми инстансом студента внутри (если студента отредактировали). (Я про vue почти ничего не знаю — допускаю, что мой вопрос звучит наивно)


  2. Ваш пример со студентами — computed же ведь и правда зависит от каждого студента, а не только от самого массива. Если сделать students[1234].age = 19, массив не поменялся, но computed все равно надо пересчитать. Или я опять что-то не так понял?


  1. Селекторы и мемоизация это бич React-а. Типовое решение (но есть альтернативы в виде mobX к примеру). Но когда берёшь observable модель, последнее что хочется делать, это писать велосипеды с мемоизацией и селекторами :) Понятно, что уходя от Vue в деле бизнес-логики можно её переписать на что угодно и какой-угодно изолентой подцепить к Vue componentTree. Но какой смысл? Оставляя за Vue только роль шаблонизатора?
  2. Проблема не в пересчёте. Если students[1234].age меняется, то и computed значение основанное на нём разумеется тоже должно обновиться. И Vue2 его обновит. Проблема в том, что Vue2 не способен даже считать уже закешированное значение без копирования абсолютно всех его зависимостей. Там где продвинутые (или лучше сказать "нормальные"?) observable решения просто запишут b зависит от a, где a зависит от 5000 других значений, vue2 запишет ему эти зависимости напрямую. А учитывая что во Vue2 буквально все bind-ы это тоже computed, то мы оказываемся в ситуации что любой render заставляет CPU 99% времени копировать зависимости. Фактически программа больше ничем не занимается кроме как копированием зависимостей.

И да. Я уже выше писал, что это можно обойти, например, отказавшись от computed и руками разрулив всё через watch-еры. Или отказавшись от Vue observables в пользу каких-нибудь более продуманных. Например затащить в проект RxJS или MobX. Да или то же самое решение с reselect, что я в итоге написал для React + Redux. Но зачем? Что такого ценного во Vue остаётся, чтобы это того стоило?

  1. спасибо за пояснение. полностью согласен
  2. ага, я неправильно понял пример. перешел по ссылке на codesandbox, поигрался. действительно, выглядит очень странно и даже контринтуитивно.
Очень хорошая ветка. Но есть нюансы:
Вычисления computed кэшируются и перевычисляются только при реальном изменении зависимостей. Вот небольшой пример: jsfiddle.net/hz2adcrn/1
А от лишних observables выручает object.freeze (и про это есть в документации почти в самом начале: ru.vuejs.org/v2/guide/instance.html#%D0%94%D0%B0%D0%BD%D0%BD%D1%8B%D0%B5-%D0%B8-%D0%BC%D0%B5%D1%82%D0%BE%D0%B4%D1%8B :) ).

И да, у меня был проект, в котором выводился график посещаемости для сотни сотрудников за пару лет работы с фильтрами и прочим на основе данных из СКУД. Там сильно больше 5000 объектов в исходных данных было. И computed перестали тормозить, как только я заморозил сырые данные (и данные проходов, и остальная неизменяемая НСИ, загруженная с бэкэнда). При этом все computed продолжали вычисляться — ведь в зависимостях у них остались значения фильтров.
Если же 5000 строк «глубоких» объектов надо менять, то тут надо действительно что-то придумывать, но ничего сильно костыльного не будет.
Если же 5000 строк «глубоких» объектов надо менять, то тут надо действительно что-то придумывать, но ничего сильно костыльного не будет.

Имхо это вопрос дефиниции костыля :)


Нужно будет на всех уровнях где большой список зависимостей рвать этот список. Например watcher-ами. А это дополнительный слой асинхронщины, там где её не ждёшь. Может вылиться во что-нибудь неприятное, вроде неконсистентного рендера. Ну и попахивает такой код, если честно. Вместо очевидного древа вычислений чуть ли не ручное указание зависимостей (тут завуалированный пинок в сторону React, которые своими хуками заставляет это делать).


Про freeze спасибо. Полагаю, что 2 года назад этого ещё не было, т.к. все мои поиски приводили к стороннему плагину, которые, наверное, делал что-то подобное но "на свой страх и риск".


Правда вот тут я уже начинаю плыть в вопросе организации подписки на изменение отдельных элементов массива (не их полей, а именно самих элементов, скажем students[123]. Скажем данные студентов можно менять иммутабельно (нечто вроде Vue.set(students, 1234, { ...student, age: newAge }). Но нужно ещё организовать точечные обновления компонент, которые завязаны на данные полей студента. Т.е. условно передав <StudentLabel v-bind:student={student[1234]}/>, я хочу чтобы оно само догадалось обновиться если student[1234] изменился. Но я не помню как точно работает передача props во Vue2. Оно сравнит их по === и в случае несоответствия принудительно перерендерит <StudenLabel/>? Или оно вообще всегда будет это делать, ничего не проверяя?

При этом все computed продолжали вычисляться — ведь в зависимостях у них остались значения фильтров.

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

Ну, тут можно пересчитывать все однократно, если сделать this.data = Object.freeze(modifiedData), то все однократно пересчитается, при этом лишних обзерверов не будет. Но при использовании vuex оно примерно так и будет само. Ну еще можно заменить массив на объект с ключами вместо бывших индексов, чтобы пересчет был не при изменении любого элемента, а только по цепочке от нужного. Кстати, вроде в vue3 это поправили. Много разных способов есть, нужный зависит от контекста задачи.
Только для тоталов это не очень поможет, там все равно придется отвязывать зависимости, чтобы лишних циклов не плодить, а сделать "- старое значение + новое значение". Но я ни одной либы не знаю, в которой этот вопрос нормально сделан. В любом случае порог, до которого можно не заниматься оптимизацией в vue достаточно высок. При этом даже самые тривиальные приемы оптимизации (как выше) дают существенный эффект при использовании в узких местах.

Если я вас понял, то получается примерно та же самая схема, что была бы в случае redux + reselect (1 реактивная переменная + иммутабельность + ререндер почти всего, почти всегда).


Рискну предположить, что на KnockoutJS и RxJS оно бы завелось без каких-бы то ни было приседаний. Просто решение в лоб. Но точно сказать не могу, т.к. времени поиграться не было.

В vue ререндер идет только у узлов, соджержащих реально изменившиеся данные, так что даже полный пересчет сильно легче. На сам DOM нагрузка минимальная. Это поведение сильно снижает головную боль по сравнению с тем же реактом.
В vue ререндер идет только у узлов, соджержащих реально изменившиеся данные

ЕМНИП то разница там такая:


  • React просто вызывает метод-компонент целиком и получает vDOM древо, которое затем реконсилирует. Разницу накатывает в DOM.
  • Vue ahead-of-time компилирует render метод сам, и выдаёт там следующую оптимизацию — выносит статические вещи наружу, тем самым обеспечив им неизменность по ===, что часто уменьшает глубину проверки во время реконсиляции

Т.е. они делают практически одно и то же, но у Vue есть небольшой козырь в рукаве. Не думаю что это сильно что-то меняет. Или сейчас всё иначе работает?


Точечные обновления делают Svelte и KnockoutJS. Вот про них действительно можно сказать, что "ререндер идет только у узлов, соджержащих реально изменившиеся данные". Без всяких "но" :) Ибо там никакого virtualDom под капотом нет и не планировалось.


В описываемой ситуации я не вижу существенной разницы между количеством работы, которое сделает React и какое сделать Vue. И там и там оба framework-а будут рендерить свои vDom деревья целиком, во всех связанных и не связанных местах. И там и там будет запущена реконсиляция. И там и там по её результатам будут произведены нужные модификации DOM. Просто Vue не будет трогать совсем уж лишние ноды, которые умный компилятор вынесет в константы. Я прав?

UFO just landed and posted this here

"Совсем уж" — ноды у которых нет v-*. React будет их проверять, а Vue не будет. В этом разница. Поэтому добавка. Правда есть плагины для babel, которые делают почти ту же самую оптимизацию, что и компилятор Vue. Я с ними пока не игрался.


В остальном поведение, полагаю, идентичное с React. Vue вызывает render метод, в котором остались тоьлко ноды с v-*. Vue сверяет их с предыдущим vDom-древом на предмет различий. Vue накатывает различия на реальный dom.


Т.е. если говорить про vDom, то Vue будет трогать неизменившиеся ноды, т.к. он не знает о том, что изменилось, а что нет. Если горовить про браузерный dom, то Vue не будет трогать те ноды, в которых нет различий. В этом и суть virtualDOM. Впрочем Preact раньше (возможно и сейчас) обходится без промеуточных прослоек и сразу реконсилирует реальный DOM.

vue не будет вызывать рендер компонентов, которые не зависят от изменившихся данных. Из-за этого есть (были в версии 2) некоторые неудобства, например важность :key, но это все мелочи. В реакте решение простое — не использовать фичу, а использовать редакс, мобикс, вот хуки с недавнего времени появились, которые решают в т.ч. эту проблему :)
Просто в vue это было с самого начала (условного. в v2 точно было, а v1 я не использовал).
habr.com/ru/company/plarium/blog/426197 не бывает в принципе.

vue не будет вызывать рендер компонентов, которые не зависят от изменившихся данных.

React.memo


В реакте решение простое — не использовать фичу, а использовать редакс

Redux тут совсем не причём, если честно. Он решает проблему props.hell, а не проблему перерисовки нетронутых компонент. И да он тоже использует react.memo под капотом

React.memo
Это про результат вызова, а не про его отсутствие :)
Но да, грубо говоря, решает ту же задачу.
Redux тут совсем не причём, если честно. Он решает проблему props.hell
Ну так ничего не мешает ему решать более одной проблемы. Хотя действительно. Хотя я сейчас прикинул — он вполне может и не решать упоминаемой проблемы.
UFO just landed and posted this here
Вам уже несколько раз именно это повторили. Вроде бы не должно быть двойственного толкования.

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

ЕМНИП для тех компонентов, которые не зависят от измененных данных, в принципе не вызывается перерендеринг.
ЕМНИП для тех компонентов, которые не зависят от измененных данных, в принципе не вызывается перерендеринг.

Не готов утверждать это наверняка, т.к. не пишу на Vue, но скорее всего так и есть. Зачем рендерить вложеные компоненты, props-ы которых не изменились. React так делает по-умолчанию, за что его многие не любят. Тот самый React.memo как раз для того чтобы этого не делать и введён.


Интересно будет взглянуть как обстоят дела во Vue3 и хуками. Т.к. природа функциональных компонент добавляет очень много проблем, и если Vue3 тоже взял себе их на вооружение, то они должны были придумать какой-нибудь свой useCallback или иную альтернативу.

Он не будет ререндерить и те v-* которые зависят от неизменившихся данных.

Будет.


Вроде бы не должно быть двойственного толкования.

Должно.


var render = function () {
    var _vm = this;
    var _h = _vm.$createElement;
    var _c = _vm._self._c || _h;
    return _c(
      "div",
      { attrs: { id: "app" } },
      [
        _c("img", {
          attrs: {
            alt: "Vue logo",
            src: require("./assets/logo.png"),
            width: "25%",
          },
        }),
        _c("HelloWorld", { attrs: { msg: _vm.test() } }),
      ],
      1
    );
  };

Вот так ^ выглядит render метод вот этого:


<template>
  <div id="app">
    <img alt="Vue logo" src="./assets/logo.png" width="25%">
    <HelloWorld v-bind:msg="test()"/> 
  </div>
</template>

_c это аналог React.createElement. Часто это называют pragma-ой. Render метод возвращает новое vDom древо с каждым рендером. Всегда. Без исключения. А потом сравнивает между собой старое и новое древо. Найдя отличия Vue накатывает их на браузерный DOM. Точно так же работает React и другие реактивные библиотеки\фреймворки с virtual dom под капотом.


Поэтому тут 2 рендера:


  • рендер vDom tree (вызов .render())
  • рендер наживую в браузерном DOM-е (.appendChild, .remove, .insertAdjacentHTML, setAttribute и пр.)

Первый легковесный, второй тяжёлый. 1-ый вызывает 2-й. 2-й должен быть предельно производительным. 1-ый же туп как пробка — рендерит всё и всегда (в рамках своего компонента). Речь выше идёт про 1-ый.


В примере выше нет статически вынесенных нод, про которые я писал выше. Но вообще Vue так умеет (видимо в песочнице не все флаги включены). В этом случае render будет немного более сложным.


Искренне надеюсь, что теперь у вас есть "двойное толкование". И интерес к тому, что на самом деле творится под капотом Vue.

UFO just landed and posted this here
как я понимаю — при изменении данных вызывается ререндер только данного компонента в Virtual DOM

Это никак не противоречит ничему что я сказал выше


Вы думаете, что при изменении ререндятся все компоненты в рамках своего компонента, что на мой взгляд не верно.

Проблема тут только в том, что я так не думаю :)


vDomNode и Component это разные понятия. К примеру вот так выглядит типичная React vDomNode:


const reactVDomNode = {
  $$typeof: Symbol(react.element),
  key: null,
  props: { children: '123' },
  ref: null,
  type: 'b',
  _owner: null,
  _store: { validated: false },
  _self: null,
  _source: null,
};

Похожим образом выглядит и Vue2 virtual dom node. Это просто небольшой объект, который содержит:


  • тип ноды (ссылку на компонент или имя тега)
  • её props-ы

В общем это всё вопрос терминологии. Всё самое интересное в вашей картинке зарыто слева. Там где жёлтый круг, стрелка вниз и дерево.

Речь не только про это. А про то, что в компонентах хранятся зависимости и ситуации как в habr.com/ru/company/plarium/blog/426197 не бывает в принципе.

На react можно spread в пропсах использовать. В vue2 это недоступно, в анонсах vue3 не вижу.

Если я правильно понял, это делается как-то так (vue2): gist.github.com/FragsterAt/bd5dba77245db1cd4c6896ff78a9b7c6 Это микрокомпонент с дефолтными значениями для компонента из фреймворка. На самом деле в данном случае v-bind и v-on не нужны. А вот если надо не на корень их навесить — тогда да.

Хм. По примеру непонятно как это связано с:


<div {...someProps} someOtherProps={1} />

во Vue2 & Vue3 так можно? Эта штука очень плотно используется в реальном React коде. Особенно с TS.

Всё равно ничего не понятно. Вы просто вынесли все props из someProps в какую-то отдельную wrapper сущность со слотом? Really? Где явным образом всё равно всё перечисляете, указывая default и типы? А зачем оно такое кому-нибудь нужно?

В моем примере передаются все входные параметры далее во вложенный компонент. Плюс ещё два, для которых я задал дефолтное значение, отличающееся от дефолтного значения компонента, который вложен в мой компонент. Если же на входе будет color и size, то они также попадут во вложенный компонент, для него ничего не изменится.

Входящие данные компонента можно рассматривать как объект. Если ключ объекта есть в секции props, то значение попадает в соответствующее поле (доступное в this и в this.$props), остальное — попадает в this.$attrs. И с этими данными можно работать. v-bind без параметра принимает на вход объект, ключи которого переносятся в свойства элемента.
<div v-bind="{ id: someProp, 'other-attr': otherProp }"></div>
является эквивалентом
<div v-bind:id="someProp" v-bind:other-attr="otherProp"></div>
ну, или в сокращенном синтаксисе:
<div :id="someProp" :other-attr="otherProp"></div>

Ааа. То есть код в вашем gist-е это не пример ..., а просто пример компонента? Я думал это часть решения для ....


Т.е. фактически получается что v-bind="anyPropsObject" это аналог {...anyPropsObject}?


И для <A {...propsPack1} {...propsPack2} otherProp={4}/> нужно написать <A v-bind="{ ...propsPack1, ...propsPack2 }" v-bind:otherProp="otherProp"/>?


Если всё так и больше ничего нигде велосипедить не нужно (к примеру внутри компонента, или создавая над ним обёртку), то вполне юзабельно.


Правда в случае TS и React, тут ещё срабатывает проверка типов и если propsPack1 или propsPack2 содержат некорректные данные, то оно не скомпилируется. Ну и как вишенка на торте, если указать что-нибудь типа:
<A otherProp={1} {...props}/> где type Props = { a: number } мы получим warning, о том, что otherProp={1} бесмысленно, т.к. всегда перезаписывается.

фактически получается что v-bind="anyPropsObject" это аналог {...anyPropsObject}?
Да
для <A {...propsPack1} {...propsPack2} otherProp={4}/> нужно написать <A v-bind="{ ...propsPack1, ...propsPack2 }" v-bind:otherProp="otherProp"/>
Да, только v-bind:otherProp="4"
TS и React, тут ещё срабатывает проверка типов и если propsPack1 или propsPack2 содержат некорректные данные, то оно не скомпилируется
Напрямую в шаблонах проверки типов ts нет, есть консольная версия vti (см ветку habr.com/ru/post/520022/#comment_22094558 ), которая проверяет типы в шаблонах. На досуге посмотрю, как она на это реагирует.
Уже на rc версиях перевез два проекта и две библиотеки без проблем.
UFO just landed and posted this here
Это чем-то похоже на vue-portal
Sign up to leave a comment.

Articles