Посмотрите например это: www.npmjs.com/package/mrr
Можно включить логирование как для отдельной ячейки, так и для всего графа, с выводом цепочки обновлений зависимых ячеек в консоль.
Отличное замечание. Видимо, вы пробежались вскользь по моей статье, рассмотрев только примеры кода. Что ж, мне несложно объяснить еще раз. Указанную вами статью я читал, и в своей статье на нее ссылаюсь(точнее, на ее русскоязычный перевод здесь на Хабре):
Приведенный вами пример как раз из таких. На mrr при всем желании вы не сможете сделать указанную ошибку, т.к. невозможно получить доступ к значению другого потока кроме как указав его в зависимостях:
isValid: [name => {
// делаем что-то с name
}, 'name']
На хуках же вы можете легко нарушить указанные Дэном принципы, и что хуже того, ваш код в результате может все-таки получиться рабочим(до поры до времени, или нет). Итак, избавляться от потенциальных ошибок априорно(на уровне архитектуры), или с помощью линтера — выбор за вами ;)
Кстати, если вы внесете name в список зависимостей для useEffect, то код будет работать неправильно: запрос будет отправляться сразу по мере ввода юзером данных, хотя нам по условию нужно отправлять его только по клику на кнопку.
Хороший вопрос) Именно в таком простом виде, какой я приводил, ваш способ будет удобнее. useEffect я рассматривал как наиболее общий способ выполнения сайд-эффектов. Балгодаря своим «зависимостям», он позволяет запускать сайд-эффекты не только в результате событий из ДОМа, но и при любых изменениях состояния, т.е. более обобщенно описывает взаимосвязь. Например, у нас делается аджакс запрос, в результате которого что-то меняется в состоянии, и возникает потребность сделать другой запрос. useEffect в данном случае подойдет(для описания второго запроса), т.к. он может «реагировать» на изменения состояния, а useCallback — нет.
Suspense применим только для первоначальной подгрузки данных для рендеринга компонента. В случае отправки формы с данными он вам ничем не поможет. Асинхронные компоненты тоже.
Во-первых, реактивность(коей Реакт, даже с хуками, так пока и не обзавелся) экономит код и усилия, даже если задача не очень сложная. Вот пример TodoMVC на mrr: jsfiddle.net/mikolalex/ez98hvyg/12
Чуть более 50 строк структурированного кода. Более краткой имплементации(с хуками или без) я пока не видел, если найдете — ткните носом, буду благодарен.
Другой момент(что, как я надеялся, будет понято как основная мысль статьи) — случаи, когда проект разрастается, и подходы, которые хорошо работали для простой логики, уже не так хорошо работают. Если вы изначально писали на мрр, вам буде достаточно легко сделать этот переход, если на голом Реакте — не уверен.
В-третьих(но это уже на любителя) — философия. Декларативность, использование чистых функций и т.д.
если стейта мало и он прекрасно помещается в React-компоненты, то его выносить никуда не надо
Согласен.
mrr выглядит как замена нативному API setState/useState, а не внешним библиотекам типа Redux и Mobx
А почему же вы его вместо Редакса не хотите сосватать?)
Реактивность тащит за собой лишиние церемонии в сетап тестов.
Бойлерплейт на 10 строчек, который позволяет не писать каждый раз лишнее. Вроде не так страшно)
Может стоит попытаться вынести максимум jsx в dumb компоненты, которые тестить в разы легче?
Если они dumb, то что вы будете в них тестировать? ИМХО тестировать в первую очередь нужно поведение компонента, что легко и явно делается с мрр: пишем что-то в поток и проверяем результат. Марбл диаграммы для простых случаев(а таких большинство) излишни.
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.
Да, и это кстати, забыл упомянуть, еще одно преимущество мрр. Так как на выходе вы получаете чистое дерево компонентов без многочисленных оберток.
Вы же понимаете, что всякие 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
Согласен на 100%! То, о чем вы говорите, называется гомоиконность, и ее действительно не хватает джаваскрипту. Если бы она была, инфраструктура джс была бы менее монструозной. А mrr выглядел бы изящнее и органичней)
Это все покрывается функционалом хуков, см. useState.
Но mrr — это для взаимодействия не только внутри компонента, но и между разными компонентами.
Насчет простоты: попробуйте написать хотя бы обычное TodoMVC на react-easy-state или хуках, и увидите, чем обернется эта простота(значительно большим количеством кода, как минимум).
Да, проблема действительно есть и я ее сознательно упомянул, дабы не было однобокого взгляда. Но так ли она страшна на практике — давайте подумаем.
Навигация по имени переменных — это хорошо для подключаемых модулей. Т.е, допустим, вы видите какую-то переменную, которая определена в другом модуле, кликаете по ней и переходите в другой файл к ее определению. Отлично. Но mrr — это средство управление состоянием, и состояние обычно — это не набор отдельных переменных. Если взять, к примеру, Редакс, то там состояние — это поля объекта, который формируется сложным образом. Чтобы понять, почему поле объекта приобрело то или иное значение — нужно, по сути, найти соответствующий редьюсер и просмотреть все его case'ы.
В mrr значение поля определяется явно на основе других потоков. Если это поток с этого же компонента, то вы его легко и быстро найдете — в этом же файле. Если это поток извне — то тут уже нужно искать по имени потока во всех компонентах. Найти определение внешнего потока со 100% вероятностью нельзя, как нельзя найти «определение» props вашего компонента: это невозможно, т.к. компонент может подключаться разными родительскими компонентами.
Ок, объясню подробнее.
Юзер начинает что-то вводить, через 100мс идет первый запрос, он продолжает ввод, через 200 мс сработает второй запрос. Возможна ситуация, что первый запрос закончится позже второго и будут показаны устаревшие данные.
См. диаграмму потоков:
Код, симулирующий такую ситуацию: jsfiddle.net/mikolalex/fvau6s51/6
Ситуация, кстати, не гипотетическая, а очень часто встречающаяся на практике(медленный интернет), сталкивался на многих сайтах, например на Яндекс.Расписаниях(«запаздывающий» автокомплит названия станции).
А как решается проблема «накладывания» промисов? Имею ввиду гипотетический сценарий, когда(даже с учетом дебаунса) отправляется несколько запросов с небольшим интервалом, и более ранний завершается позже, таким образом показываются устаревшие данные.
Нет, никого (из сравшихся) это уже не интересует, т.к. нужно вникать, сравнивать с другими RP реализациями, а они, видимо, дальше мейнстримовых фреймворков в своем развитии пока не дошли…
Автору спасибо за статью, невольно позавидовал вашему легкому слогу. Сейчас работаю над статьей по другой RP-библиотеке, решил добавить в нее(статью) некоторые из ваших примеров, чтобы можно было параллельно сравнить подходы… Так что, полемика будет, но чуть позже.
Почитайте Бодрийяра, "Симулякры и симуляция", там все расписано ;) В книге Постмана даны лишь некоторые частные случаи глобального механизма симуляции, описанного Бодрийяром.
Реактивный конечный автомат
Можно включить логирование как для отдельной ячейки, так и для всего графа, с выводом цепочки обновлений зависимых ячеек в консоль.
Прокачиваем React хуки с помощью FRP
Приведенный вами пример как раз из таких. На mrr при всем желании вы не сможете сделать указанную ошибку, т.к. невозможно получить доступ к значению другого потока кроме как указав его в зависимостях:
На хуках же вы можете легко нарушить указанные Дэном принципы, и что хуже того, ваш код в результате может все-таки получиться рабочим(до поры до времени, или нет). Итак, избавляться от потенциальных ошибок априорно(на уровне архитектуры), или с помощью линтера — выбор за вами ;)
Кстати, если вы внесете name в список зависимостей для useEffect, то код будет работать неправильно: запрос будет отправляться сразу по мере ввода юзером данных, хотя нам по условию нужно отправлять его только по клику на кнопку.
Прокачиваем React хуки с помощью FRP
Прокачиваем React хуки с помощью FRP
Прокачиваем React хуки с помощью FRP
В поисках серебрянной пули: акторы+FRP в Реакте
Чуть более 50 строк структурированного кода. Более краткой имплементации(с хуками или без) я пока не видел, если найдете — ткните носом, буду благодарен.
Другой момент(что, как я надеялся, будет понято как основная мысль статьи) — случаи, когда проект разрастается, и подходы, которые хорошо работали для простой логики, уже не так хорошо работают. Если вы изначально писали на мрр, вам буде достаточно легко сделать этот переход, если на голом Реакте — не уверен.
В-третьих(но это уже на любителя) — философия. Декларативность, использование чистых функций и т.д.
Согласен.
А почему же вы его вместо Редакса не хотите сосватать?)
Mrr: тотальное FRP для Реакта
Бойлерплейт на 10 строчек, который позволяет не писать каждый раз лишнее. Вроде не так страшно)
Если они dumb, то что вы будете в них тестировать? ИМХО тестировать в первую очередь нужно поведение компонента, что легко и явно делается с мрр: пишем что-то в поток и проверяем результат. Марбл диаграммы для простых случаев(а таких большинство) излишни.
Mrr: тотальное FRP для Реакта
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.
Mrr: тотальное FRP для Реакта
Mrr: тотальное FRP для Реакта
Да, и это кстати, забыл упомянуть, еще одно преимущество мрр. Так как на выходе вы получаете чистое дерево компонентов без многочисленных оберток.
Flux-redux, как мне кажется, приучил людей бездумно пихать все что можно в глобальный стейт. Чтобы различать, что нужно хранить глобально, а что нет, я вывел такое простое правило: кладите в глобальное состояние только те данные, которые будут нужны более чем одному компоненту. Например, состояние формы, до тех пор пока она не отправлена(валидация, значения полей) — это чисто локальное состояние, которое не стоит хранить в Редаксе вообще (даже сам Ден Абрамов где-то писал об этом). Но тем не менее, существует много решений, где все это обрабатывается через глобальный стор редакса.
Кроме того, мрр — это не только для внутрикомпонентного состояния. Существует также глобальный «грид»(набор взаимосвязанных ячеек) для всего приложения. Все компоненты могут «слушать» его потоки, а он, в свою очередь — потоки компонентов. Но этот аспект я в статье не осветил (хоть он в принципе и не сложный), ведь она и так весьма длинная вышла. Т.е., еще раз, в мрр есть и глобальное состояние, и при желании почти все можно хранить в нем. Возможно, опишу это еще в статье.
Нет. Если заглянуть во внутренности мрр, логика примерно такая: withMrr создает stateful React компонент со всеми методами мрр и состоянием, используя для рендера ту функцию, которую вы передали. Все данные хранятся внутри компонента. index.js ничего не запоминает.
Пока никак, и даже путей к решению проблемы пока не вижу, но пытаюсь найти.
Пока что, тестировать логику мрр придется вместе с компонентом: берете, например, enzyme, монтируете компонент, затем:
1) записываем какие-то данные в поток
2) проверяем данные в производном потоке
Примерно вот так: github.com/mikolalex/mrr/blob/master/spec/base.spec.js#L140
Mrr: тотальное FRP для Реакта
Mrr: тотальное FRP для Реакта
Но mrr — это для взаимодействия не только внутри компонента, но и между разными компонентами.
Насчет простоты: попробуйте написать хотя бы обычное TodoMVC на react-easy-state или хуках, и увидите, чем обернется эта простота(значительно большим количеством кода, как минимум).
Mrr: тотальное FRP для Реакта
Навигация по имени переменных — это хорошо для подключаемых модулей. Т.е, допустим, вы видите какую-то переменную, которая определена в другом модуле, кликаете по ней и переходите в другой файл к ее определению. Отлично. Но mrr — это средство управление состоянием, и состояние обычно — это не набор отдельных переменных. Если взять, к примеру, Редакс, то там состояние — это поля объекта, который формируется сложным образом. Чтобы понять, почему поле объекта приобрело то или иное значение — нужно, по сути, найти соответствующий редьюсер и просмотреть все его case'ы.
В mrr значение поля определяется явно на основе других потоков. Если это поток с этого же компонента, то вы его легко и быстро найдете — в этом же файле. Если это поток извне — то тут уже нужно искать по имени потока во всех компонентах. Найти определение внешнего потока со 100% вероятностью нельзя, как нельзя найти «определение» props вашего компонента: это невозможно, т.к. компонент может подключаться разными родительскими компонентами.
Как сделать поиск пользователей по GitHub без React + RxJS 6 + Recompose
Спасибо, ответ исчерпывающий.
Как сделать поиск пользователей по GitHub без React + RxJS 6 + Recompose
Юзер начинает что-то вводить, через 100мс идет первый запрос, он продолжает ввод, через 200 мс сработает второй запрос. Возможна ситуация, что первый запрос закончится позже второго и будут показаны устаревшие данные.
См. диаграмму потоков:
Код, симулирующий такую ситуацию: jsfiddle.net/mikolalex/fvau6s51/6
Ситуация, кстати, не гипотетическая, а очень часто встречающаяся на практике(медленный интернет), сталкивался на многих сайтах, например на Яндекс.Расписаниях(«запаздывающий» автокомплит названия станции).
Как сделать поиск пользователей по GitHub без React + RxJS 6 + Recompose
Объектное Реактивное Программирование
Автору спасибо за статью, невольно позавидовал вашему легкому слогу. Сейчас работаю над статьей по другой RP-библиотеке, решил добавить в нее(статью) некоторые из ваших примеров, чтобы можно было параллельно сравнить подходы… Так что, полемика будет, но чуть позже.
Чистый javascript.Классы
Социальные сети убивают общение, потому что стали похожи на телевидение
Почитайте Бодрийяра, "Симулякры и симуляция", там все расписано ;) В книге Постмана даны лишь некоторые частные случаи глобального механизма симуляции, описанного Бодрийяром.
Использование ES6 генераторов на примере koa.js
Чистые же. Автор, неужели не сталкивались с этим термином? Или читаете только англоязычную литературу?