Как стать автором
Обновить
33
0
Денис @iminside

js nerd

Отправить сообщение

да, вы всё правильно поняли, с использованием css-modules это выглядело бы так

import styles from './styles.css'

function Component(props) {
    let cn = styles.root
    
    if(props.red) cn += ' ' + styles.red
  
    return (
        <div className={cn}>...</div>
    )
}

с использованием, например, библиотеки classnames, так

import styles from './styles.css'
import classnames from 'çlassnames'

function Component(props) {
    const cn = classnames({
      [styles.root]: true,
      [styles.red]: props.red
    })
  
    return (
        <div className={cn}>...</div>
    )
}

всё что делает candy - прячет работу по формированию свойства `className` под капот

import { Div } from './styles.css'

function Component(props) {
    return (
        <Div root red={props.red}>...</Div>
    )
}

во всём остальном на выходе мы получаем тоже что и в css-modules, что-то типа

<div class="root_23sadsd red_32423xad2">...</div>

На компонентах размера побольше хорошо заметна разница в читабельности кода

Для сравнения css-modules:

const Post = (props) => {
    /* ... */ 
    return (
        <div className={styles.post}>
            <div className={styles.cover} style={{ backgroundImage: `url(${cover})` }} />
            <div className={styles.info}>
                <div className={styles.title}>{title}</div>
                <div className={styles.stats}> 
                    <span className={styles.comments}>{commentsCount}</span>
                    <span className={styles.likes}>{likesCount}</span>
                </div>
            </div>
        </div>
    )
}

candy:

const Post = (props) => {
    /* ... */ 
    return (
        <Div post>
            <Div cover __src={`url(${cover})`} />
            <Div info>
                <Div title>{title}</Div>
                <Div stats> 
                    <Span comments>{commentsCount}</Span>
                    <Span likes>{likesCount}</Span>
                </Div>
            </Div>
        </Div>
    )
}

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

Будем честны - в большинстве случаев при верстке у тегов мы максимум, что определяем - обработчики событий типа `onClick` и свойство `className`. Думаю нет ничего сложного в том, чтобы распознать, что `<Span comments>` это тег `span` со стилем class="comments"`. Откуда этот стиль берется видно по импорту, typescript плагин также подсветит ошибку при её наличии.

аа, вот вы о чем )

сейчас это можно сделать, например, так: в файле стилей определить

/* style.css */

:global .calendar_custom_classname {
    color: rebeccapurple;
}

:global .calendar_custom_tile_classname {
    color: red;
}

затем

import './style.css'

function MyApp() { 
  return ( 
    <Calendar 
    	className="calendar_custom_classname" 
    	tileClassName="calendar_custom_tile_classname" /> 
  )
}

можно конечно рассмотреть вопрос о том, чтобы `candy-loader` помимо компонентов-тегов экспортировал ссылки на локальные названия классов, тогда можно будет сочетать подход css-modules, типа

/* style.css */

.calendar_custom_classname {
    color: rebeccapurple;
}

.calendar_custom_tile_classname {
    color: red;
}
import {calendar_custom_classname, calendar_custom_tile_classname} from './style.css'

function MyApp() { 
  return (
    <Calendar 
    	className={calendar_custom_classname} 
    	tileClassName={calendar_custom_tile_classname} /> 
  )
}

тут `calendar_custom_classname` и `calendar_custom_tile_classname` будут содержать что-то типа "_calendar_custom_tile_classname_0ksfd33"

что я собственно и сделал

получаем значение из проперти. к слову, это можно вообще нативно через дата аттрибут сделать, но вроде как там возможности пока что сильно лимитированны

развивая эту тему - можно заюзать установку значений переменных через атрибут style, т.е. например (тут нужно соглашение) все свойства, начинающиеся с двойного нижнего подчеркивания

<Div name __fontSize="14px">John</Div>

конвертировать в переменные, получая на выходе

<div class="name" style="--fontSize: 14px">John</div>

доступ к которым получать через `var(...)`

.name {
	font-size: var(--fontSize);
}

А как передать не булево свойство внутрь?

изначально не правильно понял ваш замысел, подумал что вы хотите пробрасывать свойства внутрь, как в styled-components, поэтому исправляюсь и прошу первый абзац моего ответа изложить в следующей редакции:

для динамического определения какого-то свойства компонента необходимо использовать подход css-modules, а именно передачу через свойство `style`

спасибо)

Тут всё хорошо :)

<Div root red className="anotherClassName" />

на выходе даст, что-то типа

<div class="_root_78bp722 _red_53ds782 anotherClassName"></div>

т.е. значение свойства `className`, если оно определено, будет проброшено до целевого компонента

А как передать не булево свойство внутрь?

Внутрь ничего передавать не нужно, расценивайте это не как улучшение styled-components, а больше как улучшение css-modules, т.е. мы избавились от использования библиотек типа `classnames` и ручной генерации значения свойства `className`, а всё остальное осталось как и было, т.е.

.avatar {
  width: 40px;
  height: 40px;
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
  border-radius: 50%;
}
import { Div } from './styles.css'

function Avatar(props){
 	return <Div avatar style={{backgroundImage: `url(${props.src})`}} /> 
}

И более менее сложный лэйаут будет требовать десятка дивов, импорты превратятся в Div as ComponentWrapper.

В том то и дело, что всё будет гораздо проще :)

import { Div } from './styles.css'

function Layout(props){
 	return <Div wrapper>
    	<Div header />
    	<Div aside />
        <Div content>{props.children}</Div>
  		<Div footer />
  </Div>
}

при этом в стилях у нас

.wrapper{}
.header{}
.aside{}
.content{}
.footer{}

Синтетический пример, но думаю замысел понятен :)

получаем значение из проперти. к слову, это можно вообще нативно через дата аттрибут сделать, но вроде как там возможности пока что сильно лимитированны

кстати спасибо за идею! обязательно покопаю в эту сторону, дабы упростить подобное

style={{backgroundImage: `url(${props.src})`}}

Ваша подача превратила обычно скучный для меня материал в невероятно увлекательное чтиво! Спасибо огромное!

Занимательная статистика) я, конечно обращал внимание на «визуальную отсталость» азиатских сайтов, но списывал это на особенности «вкуса» которые нам не понять.

Спасибо! А что не так с госконторами и азиатским рынком? По первым подозреваю необходимость поддержки старых браузеров. На азиатском рынке та же беда?

Буду признателен, если в дальнейшем поделитесь фидбеком :)

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 и потом используются для восстановления приложения в исходное состояние. Первичное дерево я по дефолту добавил, чтоб не пусто было, справа на панелях можно поредактировать его состояние.
Вот тут можно посмотреть "механизм сворачивания узла". Не самый чистый код, делал для себя на пробу, но основные моменты можно проследить.

Информация

В рейтинге
Не участвует
Откуда
Ногинск, Москва и Московская обл., Россия
Дата рождения
Зарегистрирован
Активность