svelte/store, nanostore или любая другая реализация push системы.
Необходимо реализовать сайдбар для просмотра книжки или чего-то такого, где страницы сгруппированы по главам.
Интерфейсы примерно такие:
interface Chapter {
title: string
selected: Observable<boolean>
pages: Page[]
...
}
interface Page {
title: string
selected: Observable<boolean>
...
}
Где Observable это Rx.Observable/svelte_store.Readable/nanostores.ReadableAtom/whatever реализующее store contract, то есть push-атом.
Задача очень простая:
Отображать в навигацонном меню главу как выбранную, если пользователь кликнул по ней и попал на специальную страницу главы, или если пользователь сейчас на странице, принадлежащей главе.
Без реактивного программирования мы бы сделали так:
let selected = chapter.selected || chapter.pages.some(p => p.selected)
С потоками реализация (которую я нашёл оптимальной) становится такой:
// nanostores
const selected = computed(
[chapter.selected, ...chapter.pages.map(c => c.selected)],
(...values) => values.some(Boolean)
)
// rxjs
const selected =
zip(chapter.selected, ...chapter.pages.map(c => c.selected))
.pipe(map((...values) => values.some(Boolean)))
Во втором варианте мне ещё и пришлось найти нужный оператор. Благо, на сайте RxJs есть operator decision tree. Наличие необходимости их писать и включать в бандл, искать и запоминать мне кажется подозрительным.
А если взять библиотеку по типу S.js (pull система), то мы вернёмся почти к оригинальному виду:
const selected = computed(() => {
return
chapter.selected() || chapter.pages.some(p => p.selected())
})
Внимание, вопрос. Какой из реактивных вариантов даст меньшее потребление памяти, меньший размер бандла, меньше оверхеда и лучшую читаемость (на уровне первого сниппета)?
Pull-системы основаны на функциях, близки к нативному коду и не связывают программиста, поэтому я так за них топил. И солид тут отнюдь не лучший. У меня есть свой фаворит среди стейт менеджеров. Надеюсь, о нём узнает больше людей
свелтовский встроганный вариант отличается от вашего "оригинального вида" добавлением нескольких знаков доллара. двух или трёх, в зависимости от того, что именно вы там сторами пооборачиваете.
Свелтовский сахар действует только в свелте - вот в чём беда. Я привёл пример с интерфейсами, но чаще всего реализованы они будут классами, в которых и хочется писать реактивную логику
твоя проблема в том что ты не свойственный для компонетных UI фреймворков архитектурный патерн используешь. Кроме того если ты развернёшь "таблицы" и сделаешь Chapter как поле у Page то для рендринга этого nav bar не надо будет никакой реактивности и только один цикл.
Да, это проблема. Но проблема примера. Я хотел описать реактивный интерфейс, а не компонентный. Я даже не знаю, что может протолкнуть мой изначальный посыл лучше. Возьмём самое простое действие в push семантике: преобразование потока: const b = a.pipe(map(v => mapper (v))) А в pull? const b = () => mapper(a()) Любая функция ленивая. Если применять автоподписки, то можно никуда от функций не уходить в сторону всяких операторов Rx. Ленивость графа приводит к тому, что никто не вычислит b, пока он не понадобится. Свелтскрипт позволяет забыть об операторах, хотя он push: $: b = mapper(a) Тут проблемы все те же - "жадная" актуализация всех состояний компонента при обновлении. Свелтскрипт можно назвать целиком процедурным, ведь классы в нем используются почти "без ведома" разработчика, то есть у него нет ничего из ООП. А теперь я бы хотел рассказать про свой "фреймворк мечты": Так вот, использование классов с библиотекой, специализирующейся на реактивном программировании в объектном стиле позволяет расставить декораторы, описывать состояния, эффекты, компьютеды - всего лишь добавляя специальные декораторы. Представьте себе свелт, который компилируется в MobX-наблюдаемый класс? Это позволит расширять компоненты не слотами, а переопределениями методом у подклассов или даже экземпляров. Позволит всему приложению жить в одной реактивной системе. Если бы аналог $: в таком фреймворке трекал зависимости в рантайме, а не в теле инструкции (с чем у свелта, кстати, полно проблем), то можно было б добиться высшей производительности за счёт пропуска вызовов метки при обновлении ненужного на данный момент стейта. Разве не круто?
Обсуждают сегодня