В такой верстке сразу видно и используемые теги, и используемые стили. Это чище на вид и легче для восприятия, если знаешь правила по, которым создан и работает код.
Будем честны - в большинстве случаев при верстке у тегов мы максимум, что определяем - обработчики событий типа `onClick` и свойство `className`. Думаю нет ничего сложного в том, чтобы распознать, что `<Span comments>` это тег `span` со стилем class="comments"`. Откуда этот стиль берется видно по импорту, typescript плагин также подсветит ошибку при её наличии.
можно конечно рассмотреть вопрос о том, чтобы `candy-loader` помимо компонентов-тегов экспортировал ссылки на локальные названия классов, тогда можно будет сочетать подход css-modules, типа
получаем значение из проперти. к слову, это можно вообще нативно через дата аттрибут сделать, но вроде как там возможности пока что сильно лимитированны
развивая эту тему - можно заюзать установку значений переменных через атрибут style, т.е. например (тут нужно соглашение) все свойства, начинающиеся с двойного нижнего подчеркивания
изначально не правильно понял ваш замысел, подумал что вы хотите пробрасывать свойства внутрь, как в styled-components, поэтому исправляюсь и прошу первый абзац моего ответа изложить в следующей редакции:
для динамического определения какого-то свойства компонента необходимо использовать подход css-modules, а именно передачу через свойство `style`
Внутрь ничего передавать не нужно, расценивайте это не как улучшение styled-components, а больше как улучшение css-modules, т.е. мы избавились от использования библиотек типа `classnames` и ручной генерации значения свойства `className`, а всё остальное осталось как и было, т.е.
получаем значение из проперти. к слову, это можно вообще нативно через дата аттрибут сделать, но вроде как там возможности пока что сильно лимитированны
кстати спасибо за идею! обязательно покопаю в эту сторону, дабы упростить подобное
Занимательная статистика) я, конечно обращал внимание на «визуальную отсталость» азиатских сайтов, но списывал это на особенности «вкуса» которые нам не понять.
Whatsup изначально задумывался не для работы в паре с React, а как самостоятельный инструмент, диктующий архитектурные правила построения приложения. Прикрутить его конечно можно, но это будет сродни басне про ужа и ежа. Для React есть множество хороших стейт-менеджеров или вы хотите потестить именно управление стейтом с помощью генераторов?
Как я понял, бегло посмотрев на код, смысл всего этого очень прост: собираем и обходим в ширину генераторами приложение как дерево.
да, но только в глубину и только на старте, дальше исключительно инкрементные обновления и наоборот из глубины в направлении корня
Похоже что dom обновляется целиком (или реализация diff-рендеринга от меня ускользает)
Ускользнула) dom так же обновляется инкрементно, причем весь виртуальный дом, как в react не создается — только фрагмент относящийся к фракталу, в котором произошли изменения (загляните в раздел о мутаторах — там есть сильно упрощенный пример с тем как создается и в дальнейшем мутируется dom-элемент)
Много бойлерплейта для приложений, для реальных проектов код выйдет слишком многословным.
да, синтаксис генераторов и while(true) на первый взгляд вызывает ощущение шаблонности, с другой стороны while(true) — это управляющая конструкция "по умолчанию", в теле генератора можно целые сценарии и конечные автоматы описывать…
по генераторам — есть пропосал на добавление стрелочных генераторов (аналогов arrow func), но пока он не подает признаков жизни, видать генераторы как-то не зашли сообществу, возможно многие еще не раскусили всей их мощи, чтобы развитие языка в этом направлении как-то активизировалось
Спасибо! Вот предыдущая статья https://m.habr.com/ru/post/517078/
Примеры когда в ней устарели, ибо все те наработки мигрировали в whatsup, но мысли и рассуждения во многом остались прежними
Порой человека нужно просто подбодрить. Он учит сам, с поверхности, как видит, не подозревая, что правильнее из глубины. Он понял, что что-то не так, и к взрослым дядькам за советом пришел, рассказал как есть, а взрослые дядьки что? Статью и карму в минус загнали? Мотивация и желание у пацана сейчас наверно зашкаливают.
Если под множеством вы подразумеваете именно коллекцию, то я пожалуй изначально не правильно расценил этот термин в данном контексте.
Тем не менее позвольте всё таки продолжить мысль о преобразовании.
Небольшое отступление — представьте театр теней, мы устанавливаем фонарик напротив стены, помещаем в поток света руку и видим на стене её тень, путем различных манипуляций мы получаем зайца, волка, птицу и т.д. Затем мы добавляем второй фонарик, свет которого создает тень от этой же руки на полу. Таким образом мы одновременно получаем две тени одной руки, да, они выглядят скорее всего по разному, но это не важно, важно то, что они полностью синхронизированы с рукой и незамедлительно реагируют на её движения.
Так вот: если рука — это исходное "множество" некоторых данных, то тень — это новое "множество", полученное путём преобразования исходного, а именно проецированием трёхмерной сущности (руки) на плоскость в двухмерную сущность (тень) с учетом различных факторов, как то: угол падения света, его яркость и т.д.
Рука — это и есть фрактал, а тень — это проекция фрактала, созданная с учетом заданных факторов. Помещая один и тот же фрактал в разные условия (добавляя фонарики), мы можем получать несколько "теней" одновременно — json, html… одно выводить на экран, другое сохранять в localStorage, при этом фрактал заботится о поддержке актуальности своих проекций в ответ на изменение своего состояния (как движения руки приводят к изменению её теней), как например: пользователь, взаимодействуя с проекцией html, меняет внутреннее состояние фрактала, провоцируя изменение проекции json и, как следствие, обновление данных в хранилище. Фрактал — это как бы мост между всеми своими проекциями.
О генерации проекций: что мы делаем, когда нам нужно сериализовать модель?
Подход первый: мы пишем функцию-сериализатор, которая рекурсивно обходит все ее свойства и на выходе отдает нам объект, который по сути отражает текущее внутреннее состояние модели и всех её связей. Но что, если нам нужно, чтобы в итоговый набор попали только определенные свойства модели? — тогда мы должны сообщить сериализатору "что брать, что не брать", для этого мы используем например декоратор @serializable, которым помечаем нужные поля. В последствии мы отдаем этот объект в JSON.serialize и получаем строку, которую куда-то там отправляем и т.д.
Подход второй: мы определяем в каждой модели метод toJSON, в котором описываем порядок сериализации именно этой модели. Далее мы опять же отдаем модель в JSON.serialize и получаем тот же результат.
Но, что если точно также, как во втором подходе, мы будем определять в моделях метод toHTML, отвечающий за генерацию вида именно этой модели, а дальше мы будем отдавать модель в некий метод HTML.serialize и получать полный вид модели, с учетом всех её зависимостей.
А что если и JSON.serialize и HTML.serialize будут отдавать не разовый снимок, а последовательность снимков, в которой каждый следующий генерируется, как только в модели появились изменения, а точнее в тех её свойствах, которые участвовали в сериализации? Тогда, используя html-последовательность мы сможем обновлять изображение на экране, а данные json-последовательности будут параллельно сохраняться в хранилище. Модель будет мостом между json и html последовательностями, уйдет за кулисы и станет чем-то большим чем просто "модель", это будет некий граф, каждый узел которого может "сворачиваться" в разные представления и обеспечивать поддержку их актуальности.
Фрактал — это как раз идея о том, чтобы строить приложения в виде таких графов.
В классическом MV* подходе мы описываем граф данных M и "граф видов" V, далее отправляем оба этих графа в некий render, он их "объединяет" и мы получаем результат. В итоге: два графа один результат.
Во фрактальном подходе все наоборот: мы описываем один граф, но каждую ноду "учим" отдавать два результата. В итоге: один граф, два результата (три, четыре — это уже как фантазия позволяет). Суть в том, что в разработке обслуживать один граф проще, чем два. Конечно же, по моему сугубо личному мнению :)
Вот собственно, что я подразумевал под отображением одного множества в другие, может быть с этого примера и стоило бы начать статью, но "хорошая мысля приходит опосля".
С уважением)
P.S. На днях стукнуло в голову сделать что-то типа редактора фрактального дерева, а чтобы привязать его к конкретной задаче — взял для примера html-код, ведь это фрактал, всего один блок с детьми в виде таких же блоков и т.д.
В итоге получился редактор, состоящий из одного и того же фрактала Block, который вложен сам в себя и в зависимости от условий может сворачиваться до
View — вид предварительного просмотра
Style — редактор своих стилей
Tree — дерево навигации
Data — набор данных, которые сохраняются в localStorage и потом используются для восстановления приложения в исходное состояние. Первичное дерево я по дефолту добавил, чтоб не пусто было, справа на панелях можно поредактировать его состояние. Вот тут можно посмотреть "механизм сворачивания узла". Не самый чистый код, делал для себя на пробу, но основные моменты можно проследить.
да, вы всё правильно поняли, с использованием css-modules это выглядело бы так
с использованием, например, библиотеки classnames, так
всё что делает candy - прячет работу по формированию свойства `className` под капот
во всём остальном на выходе мы получаем тоже что и в css-modules, что-то типа
На компонентах размера побольше хорошо заметна разница в читабельности кода
Для сравнения css-modules:
candy:
В такой верстке сразу видно и используемые теги, и используемые стили. Это чище на вид и легче для восприятия, если знаешь правила по, которым создан и работает код.
Будем честны - в большинстве случаев при верстке у тегов мы максимум, что определяем - обработчики событий типа `onClick` и свойство `className`. Думаю нет ничего сложного в том, чтобы распознать, что `<Span comments>` это тег `span` со стилем
class="comments"
`. Откуда этот стиль берется видно по импорту, typescript плагин также подсветит ошибку при её наличии.аа, вот вы о чем )
сейчас это можно сделать, например, так: в файле стилей определить
затем
можно конечно рассмотреть вопрос о том, чтобы `candy-loader` помимо компонентов-тегов экспортировал ссылки на локальные названия классов, тогда можно будет сочетать подход css-modules, типа
тут `calendar_custom_classname` и `calendar_custom_tile_classname` будут содержать что-то типа "_calendar_custom_tile_classname_0ksfd33"
что я собственно и сделал
развивая эту тему - можно заюзать установку значений переменных через атрибут style, т.е. например (тут нужно соглашение) все свойства, начинающиеся с двойного нижнего подчеркивания
конвертировать в переменные, получая на выходе
доступ к которым получать через `var(...)`
изначально не правильно понял ваш замысел, подумал что вы хотите пробрасывать свойства внутрь, как в styled-components, поэтому исправляюсь и прошу первый абзац моего ответа изложить в следующей редакции:
для динамического определения какого-то свойства компонента необходимо использовать подход css-modules, а именно передачу через свойство `style`
спасибо)
Тут всё хорошо :)
на выходе даст, что-то типа
т.е. значение свойства `className`, если оно определено, будет проброшено до целевого компонента
Внутрь ничего передавать не нужно, расценивайте это не как улучшение styled-components, а больше как улучшение css-modules, т.е. мы избавились от использования библиотек типа `classnames` и ручной генерации значения свойства `className`, а всё остальное осталось как и было, т.е.
В том то и дело, что всё будет гораздо проще :)
при этом в стилях у нас
Синтетический пример, но думаю замысел понятен :)
кстати спасибо за идею! обязательно покопаю в эту сторону, дабы упростить подобное
Ваша подача превратила обычно скучный для меня материал в невероятно увлекательное чтиво! Спасибо огромное!
Занимательная статистика) я, конечно обращал внимание на «визуальную отсталость» азиатских сайтов, но списывал это на особенности «вкуса» которые нам не понять.
Спасибо! А что не так с госконторами и азиатским рынком? По первым подозреваю необходимость поддержки старых браузеров. На азиатском рынке та же беда?
Буду признателен, если в дальнейшем поделитесь фидбеком :)
Whatsup изначально задумывался не для работы в паре с React, а как самостоятельный инструмент, диктующий архитектурные правила построения приложения. Прикрутить его конечно можно, но это будет сродни басне про ужа и ежа. Для React есть множество хороших стейт-менеджеров или вы хотите потестить именно управление стейтом с помощью генераторов?
да, но только в глубину и только на старте, дальше исключительно инкрементные обновления и наоборот из глубины в направлении корня
Ускользнула) dom так же обновляется инкрементно, причем весь виртуальный дом, как в react не создается — только фрагмент относящийся к фракталу, в котором произошли изменения (загляните в раздел о мутаторах — там есть сильно упрощенный пример с тем как создается и в дальнейшем мутируется dom-элемент)
да, синтаксис генераторов и
while(true)
на первый взгляд вызывает ощущение шаблонности, с другой стороныwhile(true)
— это управляющая конструкция "по умолчанию", в теле генератора можно целые сценарии и конечные автоматы описывать…по генераторам — есть пропосал на добавление стрелочных генераторов (аналогов arrow func), но пока он не подает признаков жизни, видать генераторы как-то не зашли сообществу, возможно многие еще не раскусили всей их мощи, чтобы развитие языка в этом направлении как-то активизировалось
спасибо за фидбек! С уважением)
Спасибо! Вот предыдущая статья https://m.habr.com/ru/post/517078/
Примеры когда в ней устарели, ибо все те наработки мигрировали в whatsup, но мысли и рассуждения во многом остались прежними
Спасибо за статью!
Хотелось бы еще отдельный подробный разбор по профайлеру и отлову утечек памяти.
Расскажите плз, что за "нехороший закон"?
Порой человека нужно просто подбодрить. Он учит сам, с поверхности, как видит, не подозревая, что правильнее из глубины. Он понял, что что-то не так, и к взрослым дядькам за советом пришел, рассказал как есть, а взрослые дядьки что? Статью и карму в минус загнали? Мотивация и желание у пацана сейчас наверно зашкаливают.
Терпение мой друг, вы на правильном пути!
спасибо! на первый взгляд действительно есть что-то общее, изучу её для общего развития)
Если под множеством вы подразумеваете именно коллекцию, то я пожалуй изначально не правильно расценил этот термин в данном контексте.
Тем не менее позвольте всё таки продолжить мысль о преобразовании.
Небольшое отступление — представьте театр теней, мы устанавливаем фонарик напротив стены, помещаем в поток света руку и видим на стене её тень, путем различных манипуляций мы получаем зайца, волка, птицу и т.д. Затем мы добавляем второй фонарик, свет которого создает тень от этой же руки на полу. Таким образом мы одновременно получаем две тени одной руки, да, они выглядят скорее всего по разному, но это не важно, важно то, что они полностью синхронизированы с рукой и незамедлительно реагируют на её движения.
Так вот: если рука — это исходное "множество" некоторых данных, то тень — это новое "множество", полученное путём преобразования исходного, а именно проецированием трёхмерной сущности (руки) на плоскость в двухмерную сущность (тень) с учетом различных факторов, как то: угол падения света, его яркость и т.д.
Рука — это и есть фрактал, а тень — это проекция фрактала, созданная с учетом заданных факторов. Помещая один и тот же фрактал в разные условия (добавляя фонарики), мы можем получать несколько "теней" одновременно —
json
,html
… одно выводить на экран, другое сохранять в localStorage, при этом фрактал заботится о поддержке актуальности своих проекций в ответ на изменение своего состояния (как движения руки приводят к изменению её теней), как например: пользователь, взаимодействуя с проекциейhtml
, меняет внутреннее состояние фрактала, провоцируя изменение проекцииjson
и, как следствие, обновление данных в хранилище. Фрактал — это как бы мост между всеми своими проекциями.О генерации проекций: что мы делаем, когда нам нужно сериализовать модель?
Подход первый: мы пишем функцию-сериализатор, которая рекурсивно обходит все ее свойства и на выходе отдает нам объект, который по сути отражает текущее внутреннее состояние модели и всех её связей. Но что, если нам нужно, чтобы в итоговый набор попали только определенные свойства модели? — тогда мы должны сообщить сериализатору "что брать, что не брать", для этого мы используем например декоратор
@serializable
, которым помечаем нужные поля. В последствии мы отдаем этот объект вJSON.serialize
и получаем строку, которую куда-то там отправляем и т.д.Подход второй: мы определяем в каждой модели метод
toJSON
, в котором описываем порядок сериализации именно этой модели. Далее мы опять же отдаем модель вJSON.serialize
и получаем тот же результат.Но, что если точно также, как во втором подходе, мы будем определять в моделях метод
toHTML
, отвечающий за генерацию вида именно этой модели, а дальше мы будем отдавать модель в некий методHTML.serialize
и получать полный вид модели, с учетом всех её зависимостей.А что если и
JSON.serialize
иHTML.serialize
будут отдавать не разовый снимок, а последовательность снимков, в которой каждый следующий генерируется, как только в модели появились изменения, а точнее в тех её свойствах, которые участвовали в сериализации? Тогда, используяhtml
-последовательность мы сможем обновлять изображение на экране, а данныеjson
-последовательности будут параллельно сохраняться в хранилище. Модель будет мостом междуjson
иhtml
последовательностями, уйдет за кулисы и станет чем-то большим чем просто "модель", это будет некий граф, каждый узел которого может "сворачиваться" в разные представления и обеспечивать поддержку их актуальности.Фрактал — это как раз идея о том, чтобы строить приложения в виде таких графов.
В классическом
MV*
подходе мы описываем граф данныхM
и "граф видов"V
, далее отправляем оба этих графа в некийrender
, он их "объединяет" и мы получаем результат. В итоге: два графа один результат.Во фрактальном подходе все наоборот: мы описываем один граф, но каждую ноду "учим" отдавать два результата. В итоге: один граф, два результата (три, четыре — это уже как фантазия позволяет). Суть в том, что в разработке обслуживать один граф проще, чем два. Конечно же, по моему сугубо личному мнению :)
Вот собственно, что я подразумевал под отображением одного множества в другие, может быть с этого примера и стоило бы начать статью, но "хорошая мысля приходит опосля".
С уважением)
P.S. На днях стукнуло в голову сделать что-то типа редактора фрактального дерева, а чтобы привязать его к конкретной задаче — взял для примера html-код, ведь это фрактал, всего один блок с детьми в виде таких же блоков и т.д.
В итоге получился редактор, состоящий из одного и того же фрактала
Block
, который вложен сам в себя и в зависимости от условий может сворачиваться доView — вид предварительного просмотра
Style — редактор своих стилей
Tree — дерево навигации
Data — набор данных, которые сохраняются в localStorage и потом используются для восстановления приложения в исходное состояние. Первичное дерево я по дефолту добавил, чтоб не пусто было, справа на панелях можно поредактировать его состояние.
Вот тут можно посмотреть "механизм сворачивания узла". Не самый чистый код, делал для себя на пробу, но основные моменты можно проследить.