QML dynamic build from virtual Dom in QSyncable
Идея “React” конкретной реализациии компонентов для qml движка.
- “ускоряет создание библиотек крутых компонентов на QML” ,
- “драйвит” QML в массы на все платформы
- повышает скорость создания интерфейсов
- повышает качество разрабатываемых QML приложений
Прост текст - просто описание идеи.
Типа “проблема”
на qml мы не имеем ничего даже близко похожего на react
- Имеется проект react-qml но в нем
- JSX это XML… Это странно для QML мира , но нормально для React мира (не о низ речь) Proof
- JS много делает, хотя в qml мире есть С++
- нет mobx, а если бы был - то это тоже был бы JS. (см. п.2)
Короче:
- Проект https://github.com/longseespace/react-qml мне НЕ нравится своей “javascript нутостью”. там js инструменты разрабтки, js делает парсинг , интерпретация … - все на js.
- Проект https://github.com/grassator/react-qml - делает, то что требуется, но он
- заброшен
- работает на JS “яваскриптнутый” . много всякого кода - можно упростить.
В то же время в проекте QSyncable :
- интеграция с C++ объектами через Qt Variant (он кстати легковесный)
- быстрый c++ DIFF для инкрементальной модификации моделей, patch. proof
- Но всё ещё надо писать на QML в обычном стиле, привязывая всякие Repeater к этим моделям… (не React style, но hi QML)
- QML интерпретируется, а не строится на лету из кода
Самые очевидные преимущества React философии / технологии
React технология (я буду называть это технологией) этим и хорош, что
- описание - декларативное, исполнение императивное, с примесью “фокусов” реактивности… - компоненты соединены с логикой, встроены в нее, но выглядит всё отдельным
- нет “промежуточные перестроенией”. т.е. нет всяких аналогов Repeater , которые
- получают “состояние1” верхнего уровня, подписываются на него
- реагированием создают “состояние2” + создают элементы , уничтожают, двигают… т.е. получаются элементы которые им подконтрольны, но не управляются больше никак.
- состояние 1 - меняет qml дерево, и меняют “состояние2” , потом “состояние2” меняет qml дерево, том возможно внутри возникает еще одно “сотояние3” если там есть циклы.
- всякие
if ... else .. endif
в react системе тоже отсутствуют. а в qml часто реализуются видимостью одного из вариантов. это плохо тем, что все эти ветки реально есть в дереве и мутируют, хотя и не видны (лишняя работа и большое число проверок условий итд)
Пример как делается условие и цикл в “React JSX way”
1 | const products = [{ |
Лямбда map
это - цикл. там же может быть и filter
сразу:
1 | {data.map(row => { |
if
- будет тернарный оператор , который возвращает один или второй (или пустой) варианты. т.е. нет управления видимостью и отображения ненужного.
Идея
Представьте себе модуль типа такого . Он упрощен - нет Repeater. Вместо него есть две строки комментария.
1 | import QtQuick 2.7 |
В данном контексте нет внешних обращений.
Я предлагаю два режима
- разработка компонентов и наладка их работы (с mock моделями данных)
- использование компонентов (с настоящими моделями)
Режимы можно совмещать : почти все приложение в режиме 2, только один компонент в режиме 1, который разрабатываем.
Режим разработки компонента
Пишем такой код файла с разметкой:
Тут
CC
это “специальное имя” , эта строка в рабочем режиме пропадет, а СС будет замена в контексте на “магию”.
1 | // file : In.qml |
Файл “someJsFile.js”
1 | // file : someJsFile.js |
React.Placeholer
- get self content items from function
- get to self parent and find self children index by self id check
- insert siblings before self
- React.Placeholer - not remove self from parent, but set visible=false and set 0x0 size
React.Placeholer usage examples
1 | // load mock elemets from other module |
Это покрывает более 80% сценариев. + если функция вернет []
это как бы условная if ... endif
логика.
Такой код легко отлаживать.
Режим нормальной работы
Файл In.qml
обрабатывается утилитой превращаясь в In_compiled.qml
. Импорт js файла с сонтекстом CC удаляется. _compiled файл добавляется со случайным именем.
1 | // file : In_compiled.qml |
Внутри JS файла “In.qml_compiled.js” :
- функции для инициализации модели через задание свойств. и только. никаких левух эффектов.
- Функции реагирования на модель, которые перестараивают instance, состояние которого функции хранят в самом элементе.
- ожидается наличие калбеков для получения кодом из этого файла элементов для некоторых своих частей. по умолчнию - пустой список.
Внутрянка компонента
Файл “In.qml_logic.js” пишем руками определяя внутренний контекст и все калбеки для внутреннего реагирования. Это одна функция - запускается при инициализации инстанса компонента. Настраивает все калбеки для внутренней логики контрола и сайд эффекты. перестранивает модель данных контекста.
Итого там доступно две модели
- модель контекста которая приехала из режима разработки - это то что становится свойствами компонента
- модель виртуального DOM, так сказать, если так можно сказать. (не знаю зачем, для хаков наверное. “правильные пацаны” смогут написать так, чтобы туда не пришлось лазать)
Использование компонента:
1 | In_compiled { |
Как оно внутри работает ?
Есть преобразователь QSyncable список в особого вида в “настроенные элементы”. QSyncable модели внутри используются как промужуточное представление (виртуальный DOM) для перестроения интерфейса (надо отнаследоваться конечно):
- когда qml компилируется утилитой в _compiled это создает код для работы с QSyncable моделью этой структуры.
- запуск функции SGHG.reactRender();
- вычисляет эту структуру (как из json) и по ней строит QML дерево элементов, к которому привязывает каллбеки для сигналов, которые нужны
- отображаемая структура кешируется
- функции меняют эту структуру, происходит сравнение, применяется патч, и QML дерево с процессе этого перестраивается
Что это все даёт ? GOALS
- Всё ещё можно разрабатывать блоки и компоненты на QML обычным образом имея мощные модели которые легко стыкуются с с++
- Не нужны: репитеры, уловки с видимостью,
- можно описывать qml компоненты в стиле реакт на хуках имея, возможность включить в моделях mobx поведение - это очень круто, наглядно, чисто, …. много плюсов.
- можно менять управлять UI из C++ & JS через изменение модели в стиле UI QT Designer как бы меняя виджеты. Это устаревший подход, но он более безопасен т.к. управление происходит моделью UI а не самими элементами внутри engine.
- При этом можно сделать все изменения и потом применитиь их все разом - очень повышается производительность.
- У теперь настоящих компонентов, появляются настоящие “свойства”. Не требуется ничего “пробрасывать”, не требуется ничего перекрывать.
Драйвер создания массы крутых компонентов.
Наикрутейший потенциал для технологии во всех таргетах: мобайл, веб, десктоп…. новые мобильные и аппаратные платформы.
Я бы даже инвесторов поискал. ;-) хз.
Блииин….. понимаю, что очень крупная замута.
Как ее уменьшить и побить на куски? ключевые куски
- по наследнику QSyncable модели (назвать к примеру QSybcableQMLModel ) построить динамически QML объект.
- [1w] загрузить нужные модули и сделать компоненты доступными
- [2w] построить сам объект
- [2w] доработать наследника так, чтобы он был Patchable но чтобы управляемый QML при патчинге тоже перестраивался
- [1w] распарсить qml в json
- [2w] уже по этому json(qml) сгенерировать JS + данные для соответствующей QSybcableQMLModel модели в внутренние функции для работы компонента.
- [2+w] Главный JS модуль ReactQml с хелперами для связывания всего этого в целостное приложение. (соединения нескольких )
Минимальная Трудоёмкость (точность + 50%-100%) 1+2+2+1+2+2=10 недель. реально 20 недель.
При этом придется “упороться”, нужна мотивация “интересная задача, хочу сделать!”
И конкурент уже есть, походу https://proton-native.js.org/#/?id=proton-native .
Мнение по этому конкуренту:
у них, по моему, плохо, что:
- JS
- не вполне QT , больше выглядит как развитие “React Native”
Хорошо:
- wxWidgets поддерживать пытаются. т.е. это другой бекенд (не QT)
Итого по ним и сравнение с моей идеей:
- они воспринимают JSX XML как единственно верный синтаксис для компонентов в мире для любых бекендов, я считаю это неестественным.
- Они считают, что JS - язык описания логики UI , я считаю, что важнее иметь модель виртуального DOM которая будет доступна с разных языков, с++ в том числе.
- я более таргетирован в QML и QT , хочу в этом бекенде “навести порядок”. Они сосредоточились на внешней форме компонентов, в первую очередь, так, чтобы предоставить для JS сообщества нативные бекенды отрисовки (распознаю это как новый тренд, который на волне успеха React Native?)
- Это значит что цели у нас все таки разные….
- ЦА у них : JS програмисты , компании , расширяющие сферу заказов с веб на native
- ЦА у меня: QT сообщество, компании, расширяющие сверу заказов с Qt на веб и другие таргеты
___Всякое
Правильный входной код компонента должен быть НЕ (Хотя, то, что ниже будет уже очень круто. Минус только , что XML и много JS внутри)
1 | import React from "react"; |
а , лучше бы он был типа такого :
1 | import QtQuick 2.4 |
Но код создания и управления элементами генерить из qml … Это то, что остаётся сделать.