Comments 15
У вас не будет работать автокомплит имени ячейки, а также поиск места, где она определена.

Это, на самом деле, серьезнейшая проблема любого проекта посложнее каких-нибудь общеизвестных и интуитивно понятных формочек. Отсутствие хорошей навигации по коду и хороших инструментов отладки/проверки всей этой «декларативщины» (я не в плохом смысле) — это страшный тормоз для попыток применить это в сложных и больших вещах.
Да, проблема действительно есть и я ее сознательно упомянул, дабы не было однобокого взгляда. Но так ли она страшна на практике — давайте подумаем.

Навигация по имени переменных — это хорошо для подключаемых модулей. Т.е, допустим, вы видите какую-то переменную, которая определена в другом модуле, кликаете по ней и переходите в другой файл к ее определению. Отлично. Но mrr — это средство управление состоянием, и состояние обычно — это не набор отдельных переменных. Если взять, к примеру, Редакс, то там состояние — это поля объекта, который формируется сложным образом. Чтобы понять, почему поле объекта приобрело то или иное значение — нужно, по сути, найти соответствующий редьюсер и просмотреть все его case'ы.

В mrr значение поля определяется явно на основе других потоков. Если это поток с этого же компонента, то вы его легко и быстро найдете — в этом же файле. Если это поток извне — то тут уже нужно искать по имени потока во всех компонентах. Найти определение внешнего потока со 100% вероятностью нельзя, как нельзя найти «определение» props вашего компонента: это невозможно, т.к. компонент может подключаться разными родительскими компонентами.
А как с сообщениями об ошибках? Вот кто-нибудь промахнулся в названии ячейки — что он в консоли увидит?

ЗЫ: Концептуально мне ваша штука очень нравится — но я думаю, она любому понравится, кто сталкивался «лбом» с RxJS на формочках — когда код в общем-то очень логичный и прекрасно работает, но настолько перегружен RxJS-specific заморочками и терминами, что люди без опыта возни конкретно с RxJS всегда слегка так офигевают, и быстро погрузить в тему их бывает непросто.
Но точно так же у меня много опыта с Require.js и прекрасными случаями опечаток и разных проблем с именами модулей, приводящими к обрушению всего на свете, и причём частенько еще и так, что определить место конкретного обрушения было непросто.
Да, как удачно подметили в комментарии ниже, можно использовать константы.

Интересно, есть ли возможность избавиться от строковых констант в интерфейсе? В том же редаксе рекомендуют давать типам имена с помощью const, которые нормально поддерживаются инструментарием.

Наблюдая за винегретом синтаксиса и модой на транспиллеры кажется, что Javascript был бы лучше, будь он изначально Lisp. Когда код как данные и с ними можно делать что угодно не нарушая ни каких правил. :)

Согласен на 100%! То, о чем вы говорите, называется гомоиконность, и ее действительно не хватает джаваскрипту. Если бы она была, инфраструктура джс была бы менее монструозной. А mrr выглядел бы изящнее и органичней)
Есть гораздо более простой github.com/solkimicreb/react-easy-state (правда ограничен поддержкой ES6 Proxy)

import React from 'react'
import { store, view } from 'react-easy-state'

const counter = store({
  num: 0,
  incr: () => counter.num++
})

export default view(() => <button onClick={counter.incr}>{counter.num}</button>)
Это все покрывается функционалом хуков, см. useState.
Но mrr — это для взаимодействия не только внутри компонента, но и между разными компонентами.
Насчет простоты: попробуйте написать хотя бы обычное TodoMVC на react-easy-state или хуках, и увидите, чем обернется эта простота(значительно большим количеством кода, как минимум).
Well, you are right: react-easy-state is more complex that one React hook. But, ok, let's look at TodoMVC on react-easy-state. github.com/solkimicreb/react-easy-state/tree/master/examples/todo-mvc
It' longer, that mrr implementation, indeed. And, what is more important, it suffers the «shared mutable state» problem: «todos» collection is shared among different components, and mutated from them. This is completely opposite to declarative approach, and, I beleive, less reliable and scalable.
Also it would be nice if you implement «edit todo item by doubleclick» feature in your TodoMVC example.
Мне нравится эта идея, но есть некоторые вопросы:
1. Правильно ли я понял, что withMrr — это не HOC?
2. Связность между компонентами. Вы же понимаете, что всякие flux/redux/mobx придумывают ради того, чтобы не хранить логику и состояние, привязанное к компонентам. Но в примерах вы поощряете код, дающий высокую связность. Да, это лучше для маленьких приложений
3. Server-side render. В замыкании index.js, откуда экспортится `withMrr`, лежит внутреннее состояние библиотеки, т.е. стейтфул. Как это будет дружить с stateless сервером пререндера, который масштабируется горизонтально и который не должен никак знать про общее состояние или про других параллельно обрабатываемых пользователях?
4. Тайпинги для flow/ts? Строки — это не только проблемы взаимодействия с IDE, но и проблемы с типизацией.
5. Как это всё покрывать юнит-тестами? Просто всё, что есть в withMrr как чёрный ящик?
Правильно ли я понял, что withMrr — это не HOC?


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

Вы же понимаете, что всякие flux/redux/mobx придумывают ради того, чтобы не хранить логику и состояние, привязанное к компонентам.


Flux-redux, как мне кажется, приучил людей бездумно пихать все что можно в глобальный стейт. Чтобы различать, что нужно хранить глобально, а что нет, я вывел такое простое правило: кладите в глобальное состояние только те данные, которые будут нужны более чем одному компоненту. Например, состояние формы, до тех пор пока она не отправлена(валидация, значения полей) — это чисто локальное состояние, которое не стоит хранить в Редаксе вообще (даже сам Ден Абрамов где-то писал об этом). Но тем не менее, существует много решений, где все это обрабатывается через глобальный стор редакса.

Кроме того, мрр — это не только для внутрикомпонентного состояния. Существует также глобальный «грид»(набор взаимосвязанных ячеек) для всего приложения. Все компоненты могут «слушать» его потоки, а он, в свою очередь — потоки компонентов. Но этот аспект я в статье не осветил (хоть он в принципе и не сложный), ведь она и так весьма длинная вышла. Т.е., еще раз, в мрр есть и глобальное состояние, и при желании почти все можно хранить в нем. Возможно, опишу это еще в статье.

Server-side render. В замыкании index.js, откуда экспортится `withMrr`, лежит внутреннее состояние библиотеки, т.е. стейтфул


Нет. Если заглянуть во внутренности мрр, логика примерно такая: withMrr создает stateful React компонент со всеми методами мрр и состоянием, используя для рендера ту функцию, которую вы передали. Все данные хранятся внутри компонента. index.js ничего не запоминает.

Тайпинги для flow/ts?


Пока никак, и даже путей к решению проблемы пока не вижу, но пытаюсь найти.

Как это всё покрывать юнит-тестами?


Пока что, тестировать логику мрр придется вместе с компонентом: берете, например, enzyme, монтируете компонент, затем:
1) записываем какие-то данные в поток
2) проверяем данные в производном потоке
Примерно вот так: github.com/mikolalex/mrr/blob/master/spec/base.spec.js#L140

Реактивность удобна когда важна череда событий, чтобы придти в нужное состояние. У Rxjs есть приятный marbles testing. Но для интерфейса интереснее стабильные состояния. Реактивность тащит за собой лишиние церемонии в сетап тестов. В примере это хорошо видно. Может стоит попытаться вынести максимум jsx в dumb компоненты, которые тестить в разы легче?

Реактивность тащит за собой лишиние церемонии в сетап тестов.

Бойлерплейт на 10 строчек, который позволяет не писать каждый раз лишнее. Вроде не так страшно)

Может стоит попытаться вынести максимум jsx в dumb компоненты, которые тестить в разы легче?

Если они dumb, то что вы будете в них тестировать? ИМХО тестировать в первую очередь нужно поведение компонента, что легко и явно делается с мрр: пишем что-то в поток и проверяем результат. Марбл диаграммы для простых случаев(а таких большинство) излишни.
Only those users with full accounts are able to leave comments. Log in, please.