Во-первых, в 12 году уже была отличная нативная кроссплатформа - Xamarin.
Во-вторых, у вас решили не тянуть сторонние нативные зависимости, что в целом тоже имеет право на жизнь, но тогда нужно конечно же хороших нативных разработчиков привлекать. А если бы использовали готовые решения, то на RN за 2-3 дня можно реализовать функционал на 2-3 платформы + небольшой патч позже при необходимости, который на нативе требует пару недель на каждой платформе, потом пару недель отлаживать.
Это простое приложение. Такое приложение не требует реализации сложной бизнес-логики и сложной UI-логики
Это вообще ни на чем не основанное утверждение, непонятно из чего следующее. Особенно если посмотреть список приложений, которые на нем написаны. Мне особенно смешно слушать, разрабатывая не первый очень сложный проект.
В приложении будут встроенные покупки.
Разрабатывал код для покупок на RN лично несколько раз, не знал просто что оказывается нельзя.
Единственный вывод, с которым можно согласиться - писать небольшую часть имеющегося большого приложения на RN действительно сомнительная идея.
Стоит также отметить, что в среднем в RN проектах редко требуется писать нативный код, на большинстве не требуется совсем.
А что если проверить IQ и подтвержденный опыт? Не может ли это быть универсальной оценкой? Либо дополнительным срезом. Интересно было бы увидеть подобное исследование.
Статья о том, как делать не надо. Можно было бы долго объяснять почему, но на это ушла бы еще одна статья. Если кратко - SOLID это набор костыльных ООП принципов, от которых в React приложениях лучше отказаться полностью, как и от ООП.
в Go не отказались от OOP... Наследование - не единственный признак ООП
Вы ошибаетесь. Именно классы - по сути раннее связывание данных и методов (не интерфейса и методов), и наследованные - и есть ООП. И в Go ни классов, ни наследования нет. Оставили ООПшный стиль вызова функций через точку, чтоб совсем джавистов не распугать.
вы апеллируете к авторитету
Скорей даю подсказку что можно покопать самому в данном направлении, так как уже сказал что пишу длинную статью на эту тему и нет смысла ее писать здесь в комментариях. А язык Go как раз и создавали, чтобы уйти от проблем ООП языков, и успешно с этим справились - то есть над этим точно задумывались. Как и тех кто делал React - эти сами прошли по всем граблям, и каждый сегодня может сам сравнить ООП vs функции. Думаю никто в здравом уме сегодня не выберет классы как основной способ создания компонент.
Тем не менее одна из самых популярных платформ и большинство инструментов и библиотек в ней используют именно ОО подход и паттерны.
А в музыкальных трендах вашей соцсети откровенное 💩, и?) Мне бросить Pink Floyd, Кино, ZZ Top и мн. др. и пойти слушать нашу эстраду?
Я не говорю, что ООП лучше ФП, но и заявлять обратное тоже считаю некорректным
Вы руководствуетесь в суждениях хайпом, как мы уже видели, хайп сегодня относительно ООП и ФП, если не особо разбираться - "каждый инструмент хорош" (раньше кстати был что ООП это лучшая парадигма, предсказываю что скоро будет что ООП - отстой). Я стараюсь руководствоваться логикой. А по логике для каждой конкретной задачи есть только одно лучшее решение. Дальше можно набрать список задач, в которых ООП будет лучше процедур / функций, и тут можно уже начать спорить. Раннее связывание данных/функций и наследование по моему мнению хуже всегда. И я об этом поспорю с удовольствием в комментариях к статье.
Любая более-менее сложная технология неотличима от магии
Чем лучше технология, тем она проще, понятнее, и в ней меньше "магии" (KISS). И это основной показатель качества инженерии.
Хуки - совершенно чуждая концепция.
Когда то и классы были чуждой концепцией. Хотя и до сих пор - разрабы React моментально пересели на функции с хуками, и возвращаться даже не думают. Хотя я согласен - можно было сделать то же самое и "без магии". Забавно, что здесь "магию" вы уже не защищаете.
Хуки позволяют переиспользовать логику ровно в той же мере, что и обычные утилитарные функции
Нет, они могут добавлять состояние и эффекты.
любой компонент на хуках намертво к ним прибит, в то время как логика HOC полностью отделена от логики компонента
Очень странно слышать, что функция перегруженная ответственностью читается легче, чем несколько отдельных самостоятельных функций
Да, и это пожалуй единственное преимущество HOC. Вот только излишнее "отделение" логик без должной необходимости есть оверинжиниринг. В абсолютном большинстве случаев лучше вызвать 10 хуков подряд в одном компоненте, передавая туда нужные данные, чем обернуть компоненту в 10 HOCов, прокидывающи друг другу пропы - не позавидовал бы тем, кому пришлось бы работать с таким кодом.
Используя хуки useEffect(), useCallback() и useMemo() вы порождаете новую функцию. Это дополнительно нагружает GC.
Да, все эти излишние создания объектов можно было бы избежать, сделай они чуть менее сахарной реализацию хуков. Но учитывая что каждый рендер и так создает дофига объектов - элементов (а создание функции +/- = создание объекта), то можно допустить, что вряд ли это хоть как то сильно сказывается на производительности относительно постоянного пересоздания vdom. Тут уже реально замерять надо. А GC кстати может работать в свободное от рендеринга время, и даже параллельно.
Именно поэтому использование useMemo() и useCallback() получается таким противоречивым - вроде по логике нужно заворачивать в них все
С этим гемором useCallback уже научились жить более менее, но они скоро обещают добавить useEvent.
useMemo() и useCallback() можно заменить простым memoize-one
В функциональных компонентах нельзя. А в классах useCallback заменяется стрелочными функциями у this. useMemo да, в классах использовали его. И?
Если Вы прокидываете данные между HOC'ами, вы скорее всего делаете что-то неправильно. То, что Вам приходится передавать значения между хуками - это как раз следствие того, что на этот костыль наложили слишком много ответственности.
Да что вы говорите. Тот же connect у redux наверное очень плохой, как же его переписать чтоб ничего не прокидывал? контекст создавать? А есть например forwardRef из React. А значения между хуками перекидываются банальными useMemo и useCallback - они ведь как принимают, так и возвращают значения.
Если говорить предметно, про тот же MobX - там существует один единственный HOC, у которого отсутствуют описанные Васм проблемы и его использование позволяет отказаться от большей части хуков (особенно от самых неудачных), сделав код сильно более читаемым.
Я так понимаю тут речь про хранение локального состояния и функций в mobx - вот тут с удовольствием бы поспорил предметно, с примерами. В том числе рассмотрел бы возможность сделать тоже самое на основе обычного useRef без лишних библиотек.
Разрабам хочется верить что это библиотека тк фреймворки это "не круто", но по сути это фреймворк, ибо все приложение строится вокруг него. Бизнес логика обновлений запускается при монтировании компонент, бизнес логика приложения запускается при монтировании главной компоненты (обычно App) и тп. Кто то может делать по другому, но смысла в этом нет никакого. Даже подписаться на изменение чего нибудь не через React.Context ведет к багам. Выкинуть React из приложения и заменить его на другую "библиотеку" зачастую равносильно полному переписыванию.
Карбюратор - простой инструмент для ДВС
Карбюратор обладает куда более худшими ползовательскими характеристиками чем инжектор, а у нас речь про технологии, выполняющие абсолютно одно и то же. Пользователь не заметит разницы в использовании сайта что на redux, что на mobx, если они написаны с одними требованиями. Вопрос лишь в сложности реализации, поддержки и тп.
Вы приводите нелогичные примеры.
Сколько это в цифрах?
Если оборачивать каждую компоненту, vdom увеличиться в 2 раза. На огромных сайтах, запущенных на слабых [андроид] девайсах с севшей батарейкой может быть заметно. Я бы в такую историю не вписывался если есть выбор. Точные цифры можете замерить сами.
На остальные пункты я смотрю ответов не нашлось)
observer в mobx-react-lite..
Я в целом про HOC vs hook, на вашем mobx свет клином не сошелся. Хотя и там могут быть проблемы, проверять нет желания.
Я думаю что судя по его комментам он бы сказал то же и про mobx в угоду effector, а я бы сказал так про mobx и effector в угоду redux) А в соседней статье любители хайпа отказываются от effector после года мучений и в очередной раз выбирают технологию без должного анализа)
Вот только профессионалы как использовали redux и не имели с ним никаких проблем, так и используют. Потому что это самый простой, а значит лучший инструмент.
Функциональный стиль не является плюсом - это просто инструмент, такой же как и ООП
В современных языках типа Go и фреймворках типа React (да это фреймворк) от ООП отказались не просто так. И создатель Java признавал что зря добавил классы. Вот про это скоро напишу статью и Вас тоже приглашу.
отсутствие магии и оберток HOC
Чем проще инструмент, тем меньше с ним проблем. Например в Redux максимально простая архитектура - неизменяемое дерево состояния, и все на него подписаны через React.Context (Provider) - нет проблем с очередностью подписок, c циклическими зависимостями и мн. др.
Соответственно чем сложнее и непонятнее инструмент - тем больше потенциальных подводных камней может возникнуть. Магия это как раз совершенно неочевидные большинству разработчиков, непривычные вещи типа makeAutoObservable и пр.
К сожалению не все разработчики чувствуют простоту архитектуры, и пресловутую "магию" - и часто ведутся на хайп, как в вашем случае. Хотя это главная задача архитектора - сделать систему настолько простой, насколько это возможно.
По поводу HOC - они 1) увеличивают vdom - по сути вместо одного слоя становится два (x2), что ухудшает производительность и отладку, стектрейс 2) усложняет типизацию - со всеми этими обертками часто сложно "прокинуть" нужный тип компоненты если он generic 3) увеличивает вложенность - компоненту можно обернуть в 5 HOC, либо в ней вызвать 5 hook подряд - во втором случае код будет куда более читаемый. Во первых видна последовательность вызовов, и можно легкочитаемо прокинуть данные из одного hook в другой. Тогда как в первом варианте придется добавлять пропы возвращаемым компонентам непонятно кому что.
А можете подсказать какие именно бенчмарки использовали для оценки производительности того же redux и других библиотек? О нем есть много мифов, в том числе что нельзя создать несколько сторов (можно), нельзя использовать изменяемое состояние (можно, но подписаться на него нельзя, для этого можно сделать отдельное хэш поле) и тп, много бойлерплейта (с RTK нет), и как раз про производительность.
На практике, в том числе на больших проектах, наблюдал проблемы производительность только один раз, но это было приложение чата на React Native, запущенное исключительно на андроиде, где в едином redux store хранилась даже тема, на которую были подписаны абсолютно все компоненты (facepalm).
Главное преимущество Redux это как раз его максимальная простота (можно на коленке написать за вечер), функциональный стиль (есть мнение, что все что сделано на классах по умолчанию плохо спроектировано, но холивар предлагаю не начинать - на это будет отдельная статья), отсутствие магии и оберток HOC (в функциональных компонентах). Любая проблема, которая когда либо возникала, имеет решение на redux - сюрпризов уже не будет.
PS. По поводу effector - многим одного взгляда на его апи и финальный код было достаточно, чтоб не переходить с mobx/redux, и как уже сказано в комментариях многие проблемы были понятны уже давно. Конечно странно что даже в таких огромных компаниях часто следую хайпу, но спасибо что написали эту статью - спорить теперь будет куда легче.
У меня другой опыт - я насмотрелся на опытных разработчиков, реализовывающих "каждый чих" самостоятельно, и все это многократно переписывал. В 95% случаев (если не чаще) все это работает плохо, забаговано, и на больших проектах не подлежит исправлению кроме как "выкинуть и написать с нуля". Про очень многие из лучших паттернов они даже и не в курсе (нормализация, optimistic response и мн. др.). Эти разработчики кстати чаще всего сами не видят никаких проблем в своем коде, и уж тем более не видят проблем в UX приложения.
Ваша статья вышла почти одновременно с моей, и про похожие кейсы. Предлагаю рассмотреть библиотеку react-redux-cache, может зайдет больше чем react-query - там есть нормализация и полный доступ к хранилищу. Конечно же рад конструктивным комментариям.
Из того что вы ответили получается что вы практически реализовали свой фреймворк на базе mobx, который используете от проекта к проекту, но только не оформили его в библиотеку. Что то в этом фреймворке требует изучения далеко не очевидной конфигурации mobx (как пример где fetching всегда false), что то не реализовано совсем - нормализация, пагинация, персистентность и мн. др., тот же optimistic response, и разумеется чтобы их добавить "просто код чутка измените под эти нужды и всё, элементарно же". Вот только многое из этого не элементарно и потребует больших изменений, довольно багоемких, которые в идеале стоило бы еще и тестами покрыть.
Оформите вашу идею в библиотеку, добавьте туда многое из того что обсудили и то что есть у "конкурентов", и возможно любители mobx ее оценят.
Под классикой вы видимо подразумеваете какой то ваш предыдущий проект, так как лично я многое здесь вижу впервые.
Что ж, по порядку:
Здесь использована магия (не все любят магию) mobx с ООП (многие считают эту парадигму неудачной), обертками компонент (увеличение vdom, стектрейса). Вынесем это за скобки ибо холивар разводить не хотелось бы.
Использована какая то неизвестная мне функция asyncHelpers для debounce и отмены запросов.
Использован неизвестный мне класс ApiReq (опять ООП) в тч для кэширования запросов. Причем в данной реализации нет возможности принудительно запустить обновление данных, например через Pull to refresh - данные минуту всегда будут приходить из кэша. Неприятный баг UX.
fetching каждый раз переходит в true, а в конце в false, тем самым показывая на короткое время спинер даже если данные уже закэшированы - UI баг. Возможно потребуется серьезный рефакторинг чтобы это исправить, если не полный отказ от данной архитектуры. Тут нужно смотреть на реализацию ApiReq.
Отсутствует нормализация - плюс множество проблем консистенстности данных в приложении, и увеличивается количеств запросов к серверу. Возможно придется полностью переписать архитектуру, чтобы ее прикрутить.
Данные item можно показать еще пока не погрузились комментарии, но не в данном примере. Потребуется рефакторинг.
Легко ли прикрутить, например, персистентность, SSR и тп?
Итого, мы имеем очередную собственную реализацию управления состоянием запросов, с проблемами, требующими серьезный рефакторинг, либо вообще полное переписывание приложения в случае, если потребуется все их исправлять (а значит на больших проектах - нерешаемых). Именно поэтому лучше не городить "свои решения", а использовать библиотеку, где большинство моментов уже продумали.
По поводу debounce в RRC:
Для query используется throttling - пока идет запрос с определенными параметрами, другие с теми же параметрами отменяются.
Для мутаций используется debounce - каждая следующая мутация отменяет предыдущую, если та еще не завершилась. Для этого вторым параметром в мутации передается abortController.signal.
Завидую себе что давно завязал с нативной ios разработкой и использую React Native. Сам язык swift на начальном этапе дал понять, что инженеры в apple уже далеко не те, и будет хуже.
PS. Кстати многие нынче используют подход из JS/TS - ReSwift вместе с UIKit, и я бы так и делал.
Во-первых, в 12 году уже была отличная нативная кроссплатформа - Xamarin.
Во-вторых, у вас решили не тянуть сторонние нативные зависимости, что в целом тоже имеет право на жизнь, но тогда нужно конечно же хороших нативных разработчиков привлекать. А если бы использовали готовые решения, то на RN за 2-3 дня можно реализовать функционал на 2-3 платформы + небольшой патч позже при необходимости, который на нативе требует пару недель на каждой платформе, потом пару недель отлаживать.
Это вообще ни на чем не основанное утверждение, непонятно из чего следующее. Особенно если посмотреть список приложений, которые на нем написаны. Мне особенно смешно слушать, разрабатывая не первый очень сложный проект.
Разрабатывал код для покупок на RN лично несколько раз, не знал просто что оказывается нельзя.
Единственный вывод, с которым можно согласиться - писать небольшую часть имеющегося большого приложения на RN действительно сомнительная идея.
Стоит также отметить, что в среднем в RN проектах редко требуется писать нативный код, на большинстве не требуется совсем.
Тут речь скорей про собесы с врачами. Хотя гос реестр врачей с их показателями IQ и подтвержденного опыта был бы кстати.
А что если проверить IQ и подтвержденный опыт? Не может ли это быть универсальной оценкой? Либо дополнительным срезом. Интересно было бы увидеть подобное исследование.
Вот если бы еще сделали движок, что использует типы TS для оптимизации.
Вот тут с вами вынужден согласиться)
Статья о том, как делать не надо. Можно было бы долго объяснять почему, но на это ушла бы еще одна статья. Если кратко - SOLID это набор костыльных ООП принципов, от которых в React приложениях лучше отказаться полностью, как и от ООП.
Вы ошибаетесь. Именно классы - по сути раннее связывание данных и методов (не интерфейса и методов), и наследованные - и есть ООП. И в Go ни классов, ни наследования нет. Оставили ООПшный стиль вызова функций через точку, чтоб совсем джавистов не распугать.
Скорей даю подсказку что можно покопать самому в данном направлении, так как уже сказал что пишу длинную статью на эту тему и нет смысла ее писать здесь в комментариях. А язык Go как раз и создавали, чтобы уйти от проблем ООП языков, и успешно с этим справились - то есть над этим точно задумывались. Как и тех кто делал React - эти сами прошли по всем граблям, и каждый сегодня может сам сравнить ООП vs функции. Думаю никто в здравом уме сегодня не выберет классы как основной способ создания компонент.
А в музыкальных трендах вашей соцсети откровенное 💩, и?) Мне бросить Pink Floyd, Кино, ZZ Top и мн. др. и пойти слушать нашу эстраду?
Вы руководствуетесь в суждениях хайпом, как мы уже видели, хайп сегодня относительно ООП и ФП, если не особо разбираться - "каждый инструмент хорош" (раньше кстати был что ООП это лучшая парадигма, предсказываю что скоро будет что ООП - отстой). Я стараюсь руководствоваться логикой. А по логике для каждой конкретной задачи есть только одно лучшее решение. Дальше можно набрать список задач, в которых ООП будет лучше процедур / функций, и тут можно уже начать спорить. Раннее связывание данных/функций и наследование по моему мнению хуже всегда. И я об этом поспорю с удовольствием в комментариях к статье.
Чем лучше технология, тем она проще, понятнее, и в ней меньше "магии" (KISS). И это основной показатель качества инженерии.
Когда то и классы были чуждой концепцией. Хотя и до сих пор - разрабы React моментально пересели на функции с хуками, и возвращаться даже не думают. Хотя я согласен - можно было сделать то же самое и "без магии". Забавно, что здесь "магию" вы уже не защищаете.
Нет, они могут добавлять состояние и эффекты.
Да, и это пожалуй единственное преимущество HOC. Вот только излишнее "отделение" логик без должной необходимости есть оверинжиниринг. В абсолютном большинстве случаев лучше вызвать 10 хуков подряд в одном компоненте, передавая туда нужные данные, чем обернуть компоненту в 10 HOCов, прокидывающи друг другу пропы - не позавидовал бы тем, кому пришлось бы работать с таким кодом.
Да, все эти излишние создания объектов можно было бы избежать, сделай они чуть менее сахарной реализацию хуков. Но учитывая что каждый рендер и так создает дофига объектов - элементов (а создание функции +/- = создание объекта), то можно допустить, что вряд ли это хоть как то сильно сказывается на производительности относительно постоянного пересоздания vdom. Тут уже реально замерять надо. А GC кстати может работать в свободное от рендеринга время, и даже параллельно.
С этим гемором useCallback уже научились жить более менее, но они скоро обещают добавить useEvent.
В функциональных компонентах нельзя. А в классах useCallback заменяется стрелочными функциями у this. useMemo да, в классах использовали его. И?
Да что вы говорите. Тот же connect у redux наверное очень плохой, как же его переписать чтоб ничего не прокидывал? контекст создавать? А есть например forwardRef из React. А значения между хуками перекидываются банальными useMemo и useCallback - они ведь как принимают, так и возвращают значения.
Я так понимаю тут речь про хранение локального состояния и функций в mobx - вот тут с удовольствием бы поспорил предметно, с примерами. В том числе рассмотрел бы возможность сделать тоже самое на основе обычного useRef без лишних библиотек.
Разрабам хочется верить что это библиотека тк фреймворки это "не круто", но по сути это фреймворк, ибо все приложение строится вокруг него. Бизнес логика обновлений запускается при монтировании компонент, бизнес логика приложения запускается при монтировании главной компоненты (обычно App) и тп. Кто то может делать по другому, но смысла в этом нет никакого. Даже подписаться на изменение чего нибудь не через React.Context ведет к багам. Выкинуть React из приложения и заменить его на другую "библиотеку" зачастую равносильно полному переписыванию.
Карбюратор обладает куда более худшими ползовательскими характеристиками чем инжектор, а у нас речь про технологии, выполняющие абсолютно одно и то же. Пользователь не заметит разницы в использовании сайта что на redux, что на mobx, если они написаны с одними требованиями. Вопрос лишь в сложности реализации, поддержки и тп.
Вы приводите нелогичные примеры.
Если оборачивать каждую компоненту, vdom увеличиться в 2 раза. На огромных сайтах, запущенных на слабых [андроид] девайсах с севшей батарейкой может быть заметно. Я бы в такую историю не вписывался если есть выбор. Точные цифры можете замерить сами.
На остальные пункты я смотрю ответов не нашлось)
Я в целом про HOC vs hook, на вашем mobx свет клином не сошелся. Хотя и там могут быть проблемы, проверять нет желания.
Я думаю что судя по его комментам он бы сказал то же и про mobx в угоду effector, а я бы сказал так про mobx и effector в угоду redux) А в соседней статье любители хайпа отказываются от effector после года мучений и в очередной раз выбирают технологию без должного анализа)
Вот только профессионалы как использовали redux и не имели с ним никаких проблем, так и используют. Потому что это самый простой, а значит лучший инструмент.
На хабре принято писать конструктивно - это же не религиозный культ очередного убийцы redux.
В современных языках типа Go и фреймворках типа React (да это фреймворк) от ООП отказались не просто так. И создатель Java признавал что зря добавил классы. Вот про это скоро напишу статью и Вас тоже приглашу.
Чем проще инструмент, тем меньше с ним проблем. Например в Redux максимально простая архитектура - неизменяемое дерево состояния, и все на него подписаны через React.Context (Provider) - нет проблем с очередностью подписок, c циклическими зависимостями и мн. др.
Соответственно чем сложнее и непонятнее инструмент - тем больше потенциальных подводных камней может возникнуть. Магия это как раз совершенно неочевидные большинству разработчиков, непривычные вещи типа makeAutoObservable и пр.
К сожалению не все разработчики чувствуют простоту архитектуры, и пресловутую "магию" - и часто ведутся на хайп, как в вашем случае. Хотя это главная задача архитектора - сделать систему настолько простой, насколько это возможно.
По поводу HOC - они 1) увеличивают vdom - по сути вместо одного слоя становится два (x2), что ухудшает производительность и отладку, стектрейс 2) усложняет типизацию - со всеми этими обертками часто сложно "прокинуть" нужный тип компоненты если он generic 3) увеличивает вложенность - компоненту можно обернуть в 5 HOC, либо в ней вызвать 5 hook подряд - во втором случае код будет куда более читаемый. Во первых видна последовательность вызовов, и можно легкочитаемо прокинуть данные из одного hook в другой. Тогда как в первом варианте придется добавлять пропы возвращаемым компонентам непонятно кому что.
Многих людей) Но холивар предлагаю здесь не устраивать. Просто есть такое мнение. Я статью пишу по этому поводу, вас обязательно позову.
О тех, что в вк наткнулись, используя очередного хайпового "убийцу redux", и о которых написано в статье.
А можете подсказать какие именно бенчмарки использовали для оценки производительности того же redux и других библиотек? О нем есть много мифов, в том числе что нельзя создать несколько сторов (можно), нельзя использовать изменяемое состояние (можно, но подписаться на него нельзя, для этого можно сделать отдельное хэш поле) и тп, много бойлерплейта (с RTK нет), и как раз про производительность.
На практике, в том числе на больших проектах, наблюдал проблемы производительность только один раз, но это было приложение чата на React Native, запущенное исключительно на андроиде, где в едином redux store хранилась даже тема, на которую были подписаны абсолютно все компоненты (facepalm).
Главное преимущество Redux это как раз его максимальная простота (можно на коленке написать за вечер), функциональный стиль (есть мнение, что все что сделано на классах по умолчанию плохо спроектировано, но холивар предлагаю не начинать - на это будет отдельная статья), отсутствие магии и оберток HOC (в функциональных компонентах). Любая проблема, которая когда либо возникала, имеет решение на redux - сюрпризов уже не будет.
Так же рекомендую ознакомиться с моей статьей о react-redux-cache (RRC) - может быть вас это заинтересует.
PS. По поводу effector - многим одного взгляда на его апи и финальный код было достаточно, чтоб не переходить с mobx/redux, и как уже сказано в комментариях многие проблемы были понятны уже давно. Конечно странно что даже в таких огромных компаниях часто следую хайпу, но спасибо что написали эту статью - спорить теперь будет куда легче.
У меня другой опыт - я насмотрелся на опытных разработчиков, реализовывающих "каждый чих" самостоятельно, и все это многократно переписывал. В 95% случаев (если не чаще) все это работает плохо, забаговано, и на больших проектах не подлежит исправлению кроме как "выкинуть и написать с нуля". Про очень многие из лучших паттернов они даже и не в курсе (нормализация, optimistic response и мн. др.). Эти разработчики кстати чаще всего сами не видят никаких проблем в своем коде, и уж тем более не видят проблем в UX приложения.
Ваша статья вышла почти одновременно с моей, и про похожие кейсы. Предлагаю рассмотреть библиотеку react-redux-cache, может зайдет больше чем react-query - там есть нормализация и полный доступ к хранилищу. Конечно же рад конструктивным комментариям.
Из того что вы ответили получается что вы практически реализовали свой фреймворк на базе mobx, который используете от проекта к проекту, но только не оформили его в библиотеку. Что то в этом фреймворке требует изучения далеко не очевидной конфигурации mobx (как пример где fetching всегда false), что то не реализовано совсем - нормализация, пагинация, персистентность и мн. др., тот же optimistic response, и разумеется чтобы их добавить "просто код чутка измените под эти нужды и всё, элементарно же". Вот только многое из этого не элементарно и потребует больших изменений, довольно багоемких, которые в идеале стоило бы еще и тестами покрыть.
Оформите вашу идею в библиотеку, добавьте туда многое из того что обсудили и то что есть у "конкурентов", и возможно любители mobx ее оценят.
Под классикой вы видимо подразумеваете какой то ваш предыдущий проект, так как лично я многое здесь вижу впервые.
Что ж, по порядку:
Здесь использована магия (не все любят магию) mobx с ООП (многие считают эту парадигму неудачной), обертками компонент (увеличение vdom, стектрейса). Вынесем это за скобки ибо холивар разводить не хотелось бы.
Использована какая то неизвестная мне функция
asyncHelpers
дляdebounce
и отмены запросов.Использован неизвестный мне класс
ApiReq
(опять ООП) в тч для кэширования запросов. Причем в данной реализации нет возможности принудительно запустить обновление данных, например через Pull to refresh - данные минуту всегда будут приходить из кэша. Неприятный баг UX.fetching каждый раз переходит в true, а в конце в false, тем самым показывая на короткое время спинер даже если данные уже закэшированы - UI баг. Возможно потребуется серьезный рефакторинг чтобы это исправить, если не полный отказ от данной архитектуры. Тут нужно смотреть на реализацию ApiReq.
Отсутствует нормализация - плюс множество проблем консистенстности данных в приложении, и увеличивается количеств запросов к серверу. Возможно придется полностью переписать архитектуру, чтобы ее прикрутить.
Данные item можно показать еще пока не погрузились комментарии, но не в данном примере. Потребуется рефакторинг.
Легко ли прикрутить, например, персистентность, SSR и тп?
Итого, мы имеем очередную собственную реализацию управления состоянием запросов, с проблемами, требующими серьезный рефакторинг, либо вообще полное переписывание приложения в случае, если потребуется все их исправлять (а значит на больших проектах - нерешаемых). Именно поэтому лучше не городить "свои решения", а использовать библиотеку, где большинство моментов уже продумали.
По поводу debounce в RRC:
Для query используется throttling - пока идет запрос с определенными параметрами, другие с теми же параметрами отменяются.
Для мутаций используется debounce - каждая следующая мутация отменяет предыдущую, если та еще не завершилась. Для этого вторым параметром в мутации передается abortController.signal.
Race condition там нет.
Dart уже много лет восходит, но никак не взойдет. Никто в здравом уме не будет менять TS на Dart, если есть выбор.
А если сравнивать с TS то Dart это изначально мертворожденный язык, который хуже чем то что уже есть.
Завидую себе что давно завязал с нативной ios разработкой и использую React Native. Сам язык swift на начальном этапе дал понять, что инженеры в apple уже далеко не те, и будет хуже.
PS. Кстати многие нынче используют подход из JS/TS - ReSwift вместе с UIKit, и я бы так и делал.