Pull to refresh

Comments 43

Непонятно, вы пишите сравнение, упоминаете мельком, что знаете о Toolkit, но в сравнении используете не его, а Sagas + чистый Redux, которые наверное года 4 как не являются интересным подходом.

В toolkit нет и бойлерплейта, про который вы пишите и хуки предоставляются и подписки делаются в несколько строчек.

Самой крутой фичей Redux всегда был Redux-Extension, который позволяет вам видеть состояние всего приложения, запросов, отдельных блоков. Имитировать/повторять/откатывать любые события. Буквально создавать весь стор из одной копипасты и дебажить/тестировать дичайшие вещи.

Насколько я понимаю https://github.com/effector/logger это все, что есть у effector'a?

Порог входа у effector низок для джунов, которые не знают ничего, тогда как устройство Redux знают практически все, кто работал с React последние лет 10. ИМХО, нужны сравнения с toolkit чтобы сделать справедливый вывод, отличный от "Effector имеет отличную документацию и уроки на русском и не имеет гибкости".

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

Как я отмечаю в статье, Effector мне понравился больше тем, что оказался понятнее и нагляднее. Не спорю, что для кого-то другого Redux лучше :)

Библиотека правда хорошая, но лапшекод можно сделать на чём угодно.

Проблема Effector и других похожих инструментов, это отсутствие визуализации.

Чтобы даже небольшой граф состояний понять, надо прочитать код и создать картинку со всеми связями у себя в голове, и это приходится делать каждый раз.

Чтобы хоть как-то избавиться от этого я пытался сделать редактор графа состояний поверх Effector, но это оказалось полумерами, которые сильно ничего не упрощали.

Кроме того, если мы говорим про DX, то нужно упомянуть немного о тестировании.

Ого, круто, тоже начинал писать свою визуализацию для связей сторов/экшенов/эффектов, но до более-менее рабочей реализации не дошел.

Может ваша реализация имеется где-то на GitHub?

Был бы рад взглянуть.

Ничего не осталось, к сожалению.
Мне показалось такое моделирование это переусложнение, так как может понадобиться любой внешний API, разные среды исполнения и т. д., и реализовать это в таком редакторе будет очень заморочено. Проще продолжать писать это привычно кодом, а ту самую необходимую визуализацию тщательно документировать в Obsidian на canvas.

Подскажите, для визуала - плашки, стрелочки - какое решение использовали? Или самописное?

Плашки и подложку в сетку сам наверстал, а для стрелочек я нашёл `react-archer`.

Наверное я открою для вас Америку, но есть такая штука - MobX. Он как раз таки дает:
- Developer eXperience на максималках.
- Кол-во лишнего кода стремиться к нулю.
- KISS на максималках.
- Максимальной возможная читаемость кода ибо он считай тупо нативный.
- Автоматический subscribe/unsubscribe.
И т.д. и т.п.

И вместо тысячи слов можно просто взглянуть на код с самыми распространенными кейсами - https://codesandbox.io/p/sandbox/adoring-banach-k8m9ss

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

Если сравнивать DX, то представляется такой образ: Redux — большая организация со сложной бюрократией, mobX — частная фирма с теми же услугами, Effector — онлайн-стартап.

redux — это Сизиф, упорно толкающий в гору огромный ком фекалий. Можно, конечно, какие-то абстракции и тулкиты использовать, но ком фекалий не прекратит быть комом фекалий. Эффектор, конечно, сильно лучше. Но зачем эти полумеры? mobx просто на голову лучше.

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

Ну то есть опыта реально нет, от слова совсем. Давайте быть честными.

Если сравнивать DX, то представляется такой образ: Redux — большая организация со сложной бюрократией, mobX — частная фирма с теми же услугами, Effector — онлайн-стартап.

Однако вы основываясь непонятно на чём делаете заключение что mobx это почти бюрократия, а effector это стартап. Скажите пожалуйста каким образом код с использованием effector'a может быть лучше чем mobx?? Просто взгляните:

Это просто тупо нативный код который работает. Проще вообще не может быть, никак, от слова совсем. Говно/лапше код который предлагает effector это просто дичь и кровь из глаз.

И вот добавим реакта
И вот добавим реакта

Всё просто максимально очевидно и понятно.
Если вы на полном серьезе считаете подход и код эффектора лучше, чище, понятнее, то у меня для вас плохие новости. Очень плохие.

Ссылка на этот код: https://stackblitz.com/edit/stackblitz-starters-omqu6z?file=src%2FApp.tsx

Не в защиту эффектора, но мобх это не про DevEx, лишнего кода там много, всякие autorun, observable, makeAutoObservable, action, reaction и т.д
KISS не работает. Чтобы два стора стора подружить нужно финт ушами сделать
Читаемость кода низкая из-за кучи декораторов и написания сторов через классы

Это какие-то устаревшие представления. Без декораторов и классов Mobx можно было использовать ещё в 2020-м: https://michel.codes/blogs/mobx6

2 стора подружить проще простого если они синглтоны - просто импортируйте один стор внутри другого. Если нельзя синглтоны из-за SSR, то решается через общий контекст. Делается 1 раз за время жизни проекта, не вижу сложностей.

autorun/reaction вообще рекомендуется избегать: https://mobx.js.org/reactions.html#use-reactions-sparingly

лишнего кода там много, всякие autorun, observable, makeAutoObservable, action, reaction и т.д

Эти 5 функций покрывают 95% потребностей.
Один makeAutoObservable(this) в конструкторе класса и не нужно писать декораторы, экшины и т.д.

Чтобы два стора подружить нужно финт ушами сделать

Не очень понимаю суть проблемы.
Если нужен один стор в другом, достаточно передать один класс в другой через конструктор или любой другой способ, который доступен в JS для взаимодействия двух инстансов классов. Mobx тут никак не ограничивает.
Либо по месту использования двух сторов можно использовать операторы, которые предоставляет Mobx - computed, reaction, autorun, when(привет операторам из effector :)

Если не используются классы, точно так же можно работать с простыми observable. Пример ниже.

Читаемость кода низкая из-за кучи декораторов и написания сторов через классы

Если не нравятся классы, можно писать функции в signal-style:

import { computed, observable, reaction } from 'mobx'

const createFullName = (initialState) => {
  const firstName = observable.box(initialState.firstName)
  const secondName = observable.box(initialState.secondName)

  const setFirstName = (name) => firstName.set(name)
  const setSecondName = (name) => secondName.set(name)

  const fullName = computed(() => firstName.get() + secondName.get())

  return {
    firstName, secondName, fullName,
    setFirstName, setSecondName,
  }
}

function main() {
  const userName = createFullName({ fistName: 'John', secondName: 'Doe' })

  // listen for fullName change and make side-effect
  const disposer = reaction(() => userName.fullName, (fullName) => console.log(fullName))

  userName.setFirstName('Jane')

  // unsubscribe from reaction
  onViewDestroy(() => disposer());
}

Лично мне в Mobx хотелось бы видеть подписку на экшины, а не только на изменение данных. В Effector и Reatom оно есть из коробки.

Лично мне в Mobx хотелось бы видеть подписку на экшины, а не только на изменение данных. В Effector и Reatom оно есть из коробки.

Ну если этот функционал вам нужен, то можно быстренько это имплементировать самому. Например так:

Вот рабочий код - https://stackblitz.com/edit/stackblitz-starters-fucwm2?file=src%2FApp.tsx

А если хочется, но лень добавлять decorateActions в конструкторы, то можно сделать финт ушами и вы получите данный функционал без изменений.

Вот рабочий код с этим приемом - https://stackblitz.com/edit/stackblitz-starters-jvlgyz?file=src%2Findex.tsx,src%2FactionSubscribe.ts,src%2FApp.tsx

Да, как вариант. Спасибо за ссылки ?

Спасибо за статью.

Когда я такие статьи читаю, у меня всегда возникает вопрос и может быть вы сможете на него ответить.

Уже достаточно давно появился context в реакте.

Почему его не используют для организации хранилища ? Может быть я не видел на столько больших проектов, где его использование было бы не уместно, но я таких проектов еще не видел.

Самый большой недостаток контекста в том, что при его обновлении происходит перерисовка всего дерева дочерних компонентов. Поэтому react context используют для данных, которые меняются редко, такие как выбор темы или языка всего приложения.

Самый большой недостаток контекста в том, что при его обновлении происходит перерисовка всего дерева дочерних компонентов.

Но контекст можно располагать хоть в каждом компоненте. Как правило перерисовка дочерних компонентов требуется.
Если мы убираем в проекте автоматическое обновление дочерних компонентов , мы сразу стлкиваемся с другой проблемой, когда надо как то вручную обновлять в дочерних компонентах данные, если это требуется. Это может быть более трудозатратно, чем сделать архитектуру где остается автоматическое обновление.

Можно пример когда это становится пробемой ?

У меня на практике был такой кейс.
Я его решил изменив архитектуру. Я её не правильно изначально составил.

Контекст сложнее тестировать, когда отказался от контекста в пользу effector сразу покрыл все тестами

Контекст сложнее тестировать

Жесть, учитывать это как аргумент конечно печально. Тестировать фронтенд Web приложения силами юнит тестов, мало того абсолютно бесполезно, так ещё и время вместо разработки тратится не в то русло. Юнит тесты это только для библиотек отличная вещь, а не для фронта Web приложения.

когда отказался от контекста в пользу effector

Какой смысл менять одно гуано, на другое гуано? Есть же очевидная вещь которая безальтернативно подходит в качестве управления состоянием - MobX, т.к. он основан на getters/setters и автоматической подпиской/отпиской.

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

MobX очень хорошая библиотека, на одном из проектов также использую ее.

Так нафига вы тогда используете всякий шлак типо Effecor'a если вы уже не отсталый и знаете что такое MobX и тем более с ним работали?

Не пойму посыл вашего комментария, всем использовать только MobX?

Ну если мы используем React, то да, альтернатив нет. В противном случае write-only говнокод.

Кто не использует MobX, будут гореть в аду?)

Ну в целом да, ибо превращает проект в помойку на ровном месте.

Почему его не используют для организации хранилища ? Может быть я не видел на столько больших проектов, где его использование было бы не уместно, но я таких проектов еще не видел.

Нет поддержки подписки на частичные изменения а-ля селекторы. Впоследствии это было решено в useSyncExternalStorage, через который большинство современных store'ов и интегрируются.

Нет поддержки подписки на частичные изменения а-ля селекторы.

А прмер можно какой нбудь ? Мне кажется это не должно быть проблемой.
Я как будет свободное время попробую два варианта.


Спасибо.

ну вот последний комментарий

https://github.com/facebook/react/issues/15156#issuecomment-1588038962

Take a look at the library react-context-slices. With this library you do it like this:

As you can see it's very easy to use and optimal. The key point is to create as many slices of Context as you need, and this library makes it extremely easy and straightforward to do it.

Этих библиотек для исправления реакта написали уже тысячи, они стабильно устаревают и через пару лет вы получите легаси написанный на некогда модных технологиях. Это уже множество раз проходили с recompose, immutable.js и redux-ducks. Не надо гнаться за всем новым и непроверенным, у библиотеки 134 загрузки в неделю.

Этих библиотек для исправления реакта написали уже тысячи, они стабильно устаревают и через пару лет

Это проблема самого реакта. Мы читем статью про очередной инструмент, о котором возможно через год уже никто не вспомнит, как сейчас редко о сагах вспоминают и редаксе.

В отличии от всех этих библиотек context входит в библиотеку реакта. По этму мне кажется любая библиотека которая в статье упоминается умрет раньше контекста.

Это не библиотека, это обёртка вот её единственный файл https://github.com/roggc/react-context-slices/blob/master/src/index.jsx

Она использует в качестве зависимостей огромный Redux-Toolkit, которой изнутри использует useSyncExternalStorage.

От контекста там одно название.

Да. Вы правы. Это совсем не решение вопроса.

Спасибо что обратили внимание. Я посмотрел в интернете и нашел решение той проблемы, которую вы описываете, с помошью context без изпользования сторонних библиотек. Очень элегантный и простой способ на мой взгляд.

Вот статья на этот счет
https://tanmaythole.medium.com/optimizing-re-render-in-react-context-d823e113a45d

А это гиф результата, которого добились в этой статье.
https://miro.medium.com/v2/resize:fit:720/format:webp/1*k7c3b7TKcZtlUaSlGVH0qQ.gif

gist
https://gist.githubusercontent.com/tanmaythole/242d9c1ab95489aebe655ff469ba3165/raw/671d8ae4247db1ccbfbfe910d0abe42fa6d774a3/App.jsx

Ну может быть... Главное в том подходе это использование ref для того что бы избежать обновление...

В любом случае context покрывает все кейсы, которые требуются для разработки. И если говорит о долговечности кода. Context это самый безопастный вариант, на сколько можно это говорить про реакт, потому что это часть реакта.

Главное в том подходе это использование ref для того что бы избежать обновление

Нет. Хранить ссылку на стор в принципе без разнице где, контекст позволяет их удобно внедрять их как зависимость.

В любом случае context покрывает все кейсы, которые требуются для разработки.

Нет не покрывает, поскольку не обеспечивает самостоятельно подписку на частичное изменение значений. Начиная с 18-ой версии React вы не можете отдать сигнал на синхронное обновление произвольного списка компонентов, потому что они могут обновится неодновременно. Когда вы обновляете контекст, то все подписанные на него компоненты обновляются одновременн, но вы не можете выбрать какие из них будут обновляться, а какие - нет. Для таких случаев, когда нужно синхронное обновление, в React специально добавили https://blog.saeloun.com/2021/12/30/react-18-useSyncExternalStore-api/

Почему не стали встраивать функционал селекторов в Context - это длинная история. Можно почитать здесь

https://github.com/reactjs/rfcs/pull/119

https://github.com/facebook/react/pull/20646

Может ещё добавят, но пока контекст можно использовать либо для констакт вроде стилей, которые если и меняются то все сразу и редко, либо для внедрения ссылок, которые суть также константы.

ну тут уже примеры надо смотреть.
Вы привели пример сначала, этот пример можно сделать.
Остальное будет время посмотрю.
Спасибо.

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

Не соглашусь, если разработчик впервые видит код с использованием effector'а, то не поймет для чего нужны импортируемые функции из этой библиотеки без прочтения документации. В особенности из-за ввода дополнительный 4-ых сущностей, тот же mobx обходился одной функцией makeAutoObservable. Порог входа ниже чем в redux, но всё ещё заметный.

Мы пришли к ипользованию zustand, количество бойлерплей кода стремится к нулю, для подключения нужно импортировать одну функцию, а на десерт - возможность подключить Redux DevTools. И размер всего в несколько килобайт тоже подкупает.

Если верить npm trends, люди всё больше используют zustand, до redux, конечно, всё ещё очень далеко, но другие варианты уже обогнал.

zustand не пробовала, но, справедливости ради, к Redux devtools эффектор тоже подключается

Неубедительно от слова совсем.

Сам на проекте перехожу с Redux на Effector и перевёл либу на effector. Господи - этот бойлерплейт от Redux так разрдражает........... Effector на самом деле хорош в этом плане - тут спорить мало кто будет

Согласен со всеми мыслями.

В своей магистерской работе исследую стейт-менеджеры, в том числе Effector. Хотел бы пообщаться с автором статьи, можно как-то связаться с вами?

Вам не кажется, что примеры выбраны не очень выразительно? Просто, основной посыл это сделать упор на DX. Но при этом примеры этот DX не совсем раскрывают. Если ваш простейший пример - это получение данных с бэка, то почему не сравнить тогда с rtk query? И весь небольшой цикл раскрыть, т.е. в том числе и обработку ошибки. В реальном проекте транспортная система будет настроена под капотом rtkquery, там же будет настроена обработка ошибок, и работать кэширование. У вас то, что скрыто за fetchName для всего этого потребует тех самых соответствующих DX телодвижений.

Далее, вы говорите про низкий порог вхождения для людей, но при этом указываете, что вариантов может быть не один и приводите вот это в пример:

const getNameFx = createEffect(fetchName);
const $name = createStore(' ').on(getNameFx.doneData, (v) => v);

Мягко говоря, это уже совсем не про DX. Тем более, если речь идет о реакте. Иными словами, кому то все таки придется преодолеть порог вхождения и реализовать/выбрать подход, который как раз и сможет понизить порог вхождения для новичков.

Статья неплохая на подумать. Но немного в смешке написана.

Sign up to leave a comment.