Pull to refresh
5
0

Пользователь

Send message
Посмотрите например это: www.npmjs.com/package/mrr
Можно включить логирование как для отдельной ячейки, так и для всего графа, с выводом цепочки обновлений зависимых ячеек в консоль.
Отличное замечание. Видимо, вы пробежались вскользь по моей статье, рассмотрев только примеры кода. Что ж, мне несложно объяснить еще раз. Указанную вами статью я читал, и в своей статье на нее ссылаюсь(точнее, на ее русскоязычный перевод здесь на Хабре):
Большинство проблем, рассмотренных в недавней статье о useEffect, на mrr в принципе невозможны

Приведенный вами пример как раз из таких. На mrr при всем желании вы не сможете сделать указанную ошибку, т.к. невозможно получить доступ к значению другого потока кроме как указав его в зависимостях:
isValid: [name => { 
   // делаем что-то с name
}, 'name']

На хуках же вы можете легко нарушить указанные Дэном принципы, и что хуже того, ваш код в результате может все-таки получиться рабочим(до поры до времени, или нет). Итак, избавляться от потенциальных ошибок априорно(на уровне архитектуры), или с помощью линтера — выбор за вами ;)
Кстати, если вы внесете name в список зависимостей для useEffect, то код будет работать неправильно: запрос будет отправляться сразу по мере ввода юзером данных, хотя нам по условию нужно отправлять его только по клику на кнопку.
Хороший вопрос) Именно в таком простом виде, какой я приводил, ваш способ будет удобнее. useEffect я рассматривал как наиболее общий способ выполнения сайд-эффектов. Балгодаря своим «зависимостям», он позволяет запускать сайд-эффекты не только в результате событий из ДОМа, но и при любых изменениях состояния, т.е. более обобщенно описывает взаимосвязь. Например, у нас делается аджакс запрос, в результате которого что-то меняется в состоянии, и возникает потребность сделать другой запрос. useEffect в данном случае подойдет(для описания второго запроса), т.к. он может «реагировать» на изменения состояния, а useCallback — нет.
Нет) Если пугают строчки, можно заменить на константы, но типы нормально не выводятся пока.
Suspense применим только для первоначальной подгрузки данных для рендеринга компонента. В случае отправки формы с данными он вам ничем не поможет. Асинхронные компоненты тоже.
чем использование mrr будет лучше обычного React
Во-первых, реактивность(коей Реакт, даже с хуками, так пока и не обзавелся) экономит код и усилия, даже если задача не очень сложная. Вот пример 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.
Да, как удачно подметили в комментарии ниже, можно использовать константы.
Правильно ли я понял, что 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

Согласен на 100%! То, о чем вы говорите, называется гомоиконность, и ее действительно не хватает джаваскрипту. Если бы она была, инфраструктура джс была бы менее монструозной. А mrr выглядел бы изящнее и органичней)
Это все покрывается функционалом хуков, см. useState.
Но mrr — это для взаимодействия не только внутри компонента, но и между разными компонентами.
Насчет простоты: попробуйте написать хотя бы обычное TodoMVC на react-easy-state или хуках, и увидите, чем обернется эта простота(значительно большим количеством кода, как минимум).
Да, проблема действительно есть и я ее сознательно упомянул, дабы не было однобокого взгляда. Но так ли она страшна на практике — давайте подумаем.

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

В mrr значение поля определяется явно на основе других потоков. Если это поток с этого же компонента, то вы его легко и быстро найдете — в этом же файле. Если это поток извне — то тут уже нужно искать по имени потока во всех компонентах. Найти определение внешнего потока со 100% вероятностью нельзя, как нельзя найти «определение» props вашего компонента: это невозможно, т.к. компонент может подключаться разными родительскими компонентами.
Ну вы же с первого раза не поняли вопроса, вот пришлось рассусоливать)
Спасибо, ответ исчерпывающий.
Ок, объясню подробнее.
Юзер начинает что-то вводить, через 100мс идет первый запрос, он продолжает ввод, через 200 мс сработает второй запрос. Возможна ситуация, что первый запрос закончится позже второго и будут показаны устаревшие данные.
См. диаграмму потоков:
time(ms): 0---------100-------200-------300-------400-------500-------
user
input:    "q"--"qu"--"qua"--"quan"--"quant"---------------------------
promise:  -----------P---------------P--------------------------------
                     ("qua")         ("quant")
                     \               \
                      \               \_GET____
                       \                       \
request:                \________GET____________\___________
                                                 \          \
resolve:  ---------------------------------------"quant"------"qua"---

Код, симулирующий такую ситуацию: jsfiddle.net/mikolalex/fvau6s51/6
Ситуация, кстати, не гипотетическая, а очень часто встречающаяся на практике(медленный интернет), сталкивался на многих сайтах, например на Яндекс.Расписаниях(«запаздывающий» автокомплит названия станции).
А как решается проблема «накладывания» промисов? Имею ввиду гипотетический сценарий, когда(даже с учетом дебаунса) отправляется несколько запросов с небольшим интервалом, и более ранний завершается позже, таким образом показываются устаревшие данные.
Нет, никого (из сравшихся) это уже не интересует, т.к. нужно вникать, сравнивать с другими RP реализациями, а они, видимо, дальше мейнстримовых фреймворков в своем развитии пока не дошли…
Автору спасибо за статью, невольно позавидовал вашему легкому слогу. Сейчас работаю над статьей по другой RP-библиотеке, решил добавить в нее(статью) некоторые из ваших примеров, чтобы можно было параллельно сравнить подходы… Так что, полемика будет, но чуть позже.
Противопоставление AjaxCall и HttpCall в примере взорвало мозг.

Почитайте Бодрийяра, "Симулякры и симуляция", там все расписано ;) В книге Постмана даны лишь некоторые частные случаи глобального механизма симуляции, описанного Бодрийяром.

В функциональном программировании есть очень важный принцип — мы должны использовать «настоящие функции».


Чистые же. Автор, неужели не сталкивались с этим термином? Или читаете только англоязычную литературу?
1

Information

Rating
Does not participate
Registered
Activity